xiatian 9 kuukautta sitten
vanhempi
commit
7ed5cdab48

+ 4 - 0
install/mysql/init/scan_central_db.sql

@@ -276,6 +276,10 @@ CREATE TABLE IF NOT EXISTS `sc_batch_paper`
     `card_number`  int(11)    NOT NULL,
     `assigned`     bit(1)     NOT NULL,
     `need_check`   bit(1)     NOT NULL,
+    `creator_id`          bigint      DEFAULT NULL,
+    `updater_id`          bigint      DEFAULT NULL,
+    `create_time`         bigint      DEFAULT NULL,
+    `update_time`         bigint      DEFAULT NULL,
     PRIMARY KEY (`batch_id`, `student_id`, `paper_number`),
     UNIQUE KEY `paper_id` (`paper_id`)
 ) ENGINE = InnoDB

+ 33 - 0
src/main/java/cn/com/qmth/scancentral/controller/admin/SubjectController.java

@@ -0,0 +1,33 @@
+package cn.com.qmth.scancentral.controller.admin;
+
+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 com.qmth.boot.api.annotation.Aac;
+import com.qmth.boot.api.constant.ApiConstant;
+
+import cn.com.qmth.scancentral.controller.BaseController;
+import cn.com.qmth.scancentral.service.SubjectService;
+import cn.com.qmth.scancentral.vo.subject.ScanProgressVo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+
+@RestController
+@Api(tags = "科目接口")
+@RequestMapping(ApiConstant.DEFAULT_URI_PREFIX + "/subject")
+@Aac(strict = false, auth = true)
+public class SubjectController extends BaseController {
+
+    @Autowired
+    private SubjectService subjectService;
+
+    @ApiOperation(value = "科目扫描进度查询")
+    @PostMapping("scan/progress")
+    public ScanProgressVo scanProgress(@RequestParam Long examId, @RequestParam(required = false) String subjectCode) {
+        return subjectService.scanProgress(examId, subjectCode);
+    }
+
+}

+ 3 - 0
src/main/java/cn/com/qmth/scancentral/dao/BatchPaperDao.java

@@ -10,4 +10,7 @@ public interface BatchPaperDao extends MppBaseMapper<BatchPaperEntity> {
 
     List<Long> findStudentIdByBatchId(@Param("batchId") Long batchId);
 
+    Integer getScanStudentCount(@Param("examId") Long examId, @Param("subjectCode") String subjectCode,
+            @Param("startTime") long startTime, @Param("endTime") long endTime);
+
 }

+ 4 - 0
src/main/java/cn/com/qmth/scancentral/dao/StudentDao.java

@@ -7,6 +7,8 @@ import cn.com.qmth.scancentral.entity.StudentEntity;
 import cn.com.qmth.scancentral.vo.*;
 import cn.com.qmth.scancentral.vo.answerquery.AnswerQueryVo;
 import cn.com.qmth.scancentral.vo.assginedcheck.AssignedCheckExport;
+import cn.com.qmth.scancentral.vo.subject.SubjectScanProgressVo;
+
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -70,4 +72,6 @@ public interface StudentDao extends BaseMapper<StudentEntity> {
             @Param("userId") Long userId, @Param("examId") Long examId);
 
     void updateAssignedCheckCount(@Param("id") Long id);
+
+    List<SubjectScanProgressVo> scanProgress(@Param("examId") Long examId, @Param("subjectCode") String subjectCode);
 }

+ 2 - 2
src/main/java/cn/com/qmth/scancentral/entity/BatchPaperEntity.java

@@ -3,11 +3,11 @@ package cn.com.qmth.scancentral.entity;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.github.jeffreyning.mybatisplus.anno.MppMultiId;
 
-import java.io.Serializable;
+import cn.com.qmth.scancentral.entity.base.AuditingWithoutIdEntity;
 
 // 批次和试卷绑定关系
 @TableName("sc_batch_paper")
-public class BatchPaperEntity implements Serializable {
+public class BatchPaperEntity extends AuditingWithoutIdEntity {
 
     private static final long serialVersionUID = 2688940244963672452L;
 

+ 2 - 0
src/main/java/cn/com/qmth/scancentral/service/BatchPaperService.java

@@ -27,4 +27,6 @@ public interface BatchPaperService extends IMppService<BatchPaperEntity> {
 
     List<BatchPaperEntity> findByBatchIdAndStudentIds(Long id, Set<Long> checkIds);
 
+    Integer getScanStudentCount(Long examId, String subjectCode, long startTime, long endTime);
+
 }

+ 5 - 0
src/main/java/cn/com/qmth/scancentral/service/StudentService.java

@@ -14,6 +14,7 @@ import cn.com.qmth.scancentral.vo.assginedcheck.AssignedTaskSaveVo;
 import cn.com.qmth.scancentral.vo.student.StudentAnswerVo;
 import cn.com.qmth.scancentral.vo.student.StudentQuery;
 import cn.com.qmth.scancentral.vo.student.StudentVo;
+import cn.com.qmth.scancentral.vo.subject.SubjectScanProgressVo;
 import cn.com.qmth.scancentral.vo.task.TaskStatusVo;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.qmth.boot.core.collection.PageResult;
@@ -162,4 +163,8 @@ public interface StudentService extends IService<StudentEntity> {
 
     StudentAnswerVo studentAnswer(Long batchId, Long studentId);
 
+    List<SubjectScanProgressVo> scanProgress(Long examId, String subjectCode);
+
+    int getUnscannedCountByExam(Long examId);
+
 }

+ 3 - 0
src/main/java/cn/com/qmth/scancentral/service/SubjectService.java

@@ -10,6 +10,7 @@ import cn.com.qmth.scancentral.bean.User;
 import cn.com.qmth.scancentral.entity.SubjectEntity;
 import cn.com.qmth.scancentral.vo.SubjectConfigVo;
 import cn.com.qmth.scancentral.vo.examinfo.SubjectConfig;
+import cn.com.qmth.scancentral.vo.subject.ScanProgressVo;
 
 public interface SubjectService extends IMppService<SubjectEntity> {
 
@@ -27,4 +28,6 @@ public interface SubjectService extends IMppService<SubjectEntity> {
 
     List<SubjectConfig> listConfigByExamId(Long examId);
 
+    ScanProgressVo scanProgress(Long examId, String subjectCode);
+
 }

+ 5 - 0
src/main/java/cn/com/qmth/scancentral/service/impl/BatchPaperServiceImpl.java

@@ -83,4 +83,9 @@ public class BatchPaperServiceImpl extends MppServiceImpl<BatchPaperDao, BatchPa
         return this.list(wrapper);
     }
 
+    @Override
+    public Integer getScanStudentCount(Long examId, String subjectCode, long startTime, long endTime) {
+        return baseMapper.getScanStudentCount(examId, subjectCode, startTime, endTime);
+    }
+
 }

+ 23 - 8
src/main/java/cn/com/qmth/scancentral/service/impl/StudentServiceImpl.java

@@ -35,6 +35,7 @@ import cn.com.qmth.scancentral.vo.paper.PaperPageCetVo;
 import cn.com.qmth.scancentral.vo.student.StudentAnswerVo;
 import cn.com.qmth.scancentral.vo.student.StudentQuery;
 import cn.com.qmth.scancentral.vo.student.StudentVo;
+import cn.com.qmth.scancentral.vo.subject.SubjectScanProgressVo;
 import cn.com.qmth.scancentral.vo.task.TaskStatusVo;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
@@ -133,7 +134,7 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, StudentEntity> i
     @Transactional
     // @Lockable(name = LockType.STUDENT, key = "#id")
     public void updateStudentAndPaper(@NotNull User user, @NotNull Long id,
-                                      @NotNull List<StudentPaperEntity> studentPaperList) {
+            @NotNull List<StudentPaperEntity> studentPaperList) {
         for (StudentPaperEntity studentPaper : studentPaperList) {
             studentPaper.setStudentId(id);
         }
@@ -354,6 +355,15 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, StudentEntity> i
         return this.count(wrapper);
     }
 
+    @Override
+    public int getUnscannedCountByExam(Long examId) {
+        QueryWrapper<StudentEntity> wrapper = new QueryWrapper<>();
+        LambdaQueryWrapper<StudentEntity> lw = wrapper.lambda();
+        lw.eq(StudentEntity::getExamId, examId);
+        lw.ne(StudentEntity::getStatus, ScanStatus.SCANNED);
+        return this.count(wrapper);
+    }
+
     @Override
     public int getAbsentSuspectCountByExam(Long examId) {
         QueryWrapper<StudentEntity> wrapper = new QueryWrapper<>();
@@ -671,7 +681,7 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, StudentEntity> i
     @Transactional
     @Override
     public void updateUploadStatus(@NotNull Long id, @NotNull UploadStatus fileUploadStatus,
-                                   @NotNull UploadStatus dataUploadStatus) {
+            @NotNull UploadStatus dataUploadStatus) {
         LambdaUpdateWrapper<StudentEntity> lw = new LambdaUpdateWrapper<>();
         lw.set(StudentEntity::getDataUploadStatus, dataUploadStatus);
         lw.set(StudentEntity::getFileUploadStatus, fileUploadStatus);
@@ -1142,8 +1152,8 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, StudentEntity> i
     }
 
     private void disposeStudent(ExportCetVo student, ExamEntity exam, List<PaperPageCetVo> pages,
-                                List<PaperCetVo> papers, String imageTransferDir, Map<String, List<QuestionEntity>> structs,
-                                Map<Integer, AnswerCardEntity> cardMap) {
+            List<PaperCetVo> papers, String imageTransferDir, Map<String, List<QuestionEntity>> structs,
+            Map<Integer, AnswerCardEntity> cardMap) {
         int subject = Integer.valueOf(student.getSubjectCode());
         if (subject > 2) {
             if (student.getExamStatus().equals(ExamStatus.ABSENT)) {
@@ -1224,7 +1234,7 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, StudentEntity> i
     }
 
     private void setCardStatus(ExportCetVo student, AnswerCardEntity card, List<PaperPageCetVo> pages,
-                               Map<Long, PaperCetVo> pmap) {
+            Map<Long, PaperCetVo> pmap) {
         int subject = Integer.valueOf(student.getSubjectCode());
         if (subject > 2) {
             setCardStatusSmall(student, card, pages, pmap);
@@ -1234,7 +1244,7 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, StudentEntity> i
     }
 
     private void setCardStatusSmall(ExportCetVo student, AnswerCardEntity card, List<PaperPageCetVo> pages,
-                                    Map<Long, PaperCetVo> pmap) {
+            Map<Long, PaperCetVo> pmap) {
         PaperPageCetVo p = pages.get(0);
         if (ExamStatus.ABSENT.equals(student.getExamStatus())) {
             if (pmap.get(p.getPaperId()).getQuestionFilled()) {
@@ -1249,7 +1259,7 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, StudentEntity> i
     }
 
     private void setCardStatusCet(ExportCetVo student, AnswerCardEntity card, List<PaperPageCetVo> pages,
-                                  Map<Long, PaperCetVo> pmap) {
+            Map<Long, PaperCetVo> pmap) {
         if (card.getPaperCount() == 1) {
             PaperPageCetVo p = pages.get(0);
             if (ExamStatus.ABSENT.equals(student.getExamStatus())) {
@@ -1342,7 +1352,7 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, StudentEntity> i
     }
 
     private String getCetAnswer(Map<String, List<QuestionEntity>> structs, List<PaperPageCetVo> pages, Long examId,
-                                String subjectCode) {
+            String subjectCode) {
         List<String> answers = new ArrayList<String>();
         List<QuestionEntity> struct = structs.get(examId + "-" + subjectCode);
         if (struct == null) {
@@ -2174,4 +2184,9 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, StudentEntity> i
         return ret;
     }
 
+    @Override
+    public List<SubjectScanProgressVo> scanProgress(Long examId, String subjectCode) {
+        return this.baseMapper.scanProgress(examId, subjectCode);
+    }
+
 }

+ 70 - 8
src/main/java/cn/com/qmth/scancentral/service/impl/SubjectServiceImpl.java

@@ -1,25 +1,46 @@
 package cn.com.qmth.scancentral.service.impl;
 
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.collections4.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.github.jeffreyning.mybatisplus.service.MppServiceImpl;
+import com.qmth.boot.core.exception.ParameterException;
+
 import cn.com.qmth.scancentral.bean.ImportSubjectDomain;
 import cn.com.qmth.scancentral.bean.SubjectConfigDomain;
 import cn.com.qmth.scancentral.bean.User;
 import cn.com.qmth.scancentral.dao.SubjectDao;
 import cn.com.qmth.scancentral.entity.SubjectEntity;
+import cn.com.qmth.scancentral.service.BatchPaperService;
+import cn.com.qmth.scancentral.service.StudentService;
 import cn.com.qmth.scancentral.service.SubjectService;
+import cn.com.qmth.scancentral.util.Calculator;
 import cn.com.qmth.scancentral.vo.SubjectConfigVo;
 import cn.com.qmth.scancentral.vo.examinfo.SubjectConfig;
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.github.jeffreyning.mybatisplus.service.MppServiceImpl;
-import com.qmth.boot.core.exception.ParameterException;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.util.*;
+import cn.com.qmth.scancentral.vo.subject.ScanProgressVo;
+import cn.com.qmth.scancentral.vo.subject.SubjectScanProgressVo;
 
 @Service
 public class SubjectServiceImpl extends MppServiceImpl<SubjectDao, SubjectEntity> implements SubjectService {
 
+    @Autowired
+    private StudentService studentService;
+
+    @Autowired
+    private BatchPaperService batchPaperService;
+
     @Transactional
     @Override
     public int cleanByExamId(Long examId) {
@@ -115,4 +136,45 @@ public class SubjectServiceImpl extends MppServiceImpl<SubjectDao, SubjectEntity
         return result;
     }
 
+    @Override
+    public ScanProgressVo scanProgress(Long examId, String subjectCode) {
+        ScanProgressVo ret = new ScanProgressVo();
+        List<SubjectScanProgressVo> subjects = studentService.scanProgress(examId, subjectCode);
+        ret.setSubjects(subjects);
+        ret.setTotal(new SubjectScanProgressVo());
+        if (CollectionUtils.isNotEmpty(subjects)) {
+            Calendar now = Calendar.getInstance();
+            long endTime = now.getTimeInMillis();
+            now.add(Calendar.MINUTE, -1);
+            long startTime = now.getTimeInMillis();
+            for (SubjectScanProgressVo vo : subjects) {
+                vo.setScannedCount(vo.getStudentCount() - vo.getUnexistCount());
+                vo.setProgress(Calculator.percentage(vo.getScannedCount(), vo.getStudentCount(), 2));
+                Integer count = batchPaperService.getScanStudentCount(examId, subjectCode, startTime, endTime);
+                if (count == null || count == 0) {
+                    vo.setEstimation("-");
+                } else {
+                    vo.setEstimation(Calculator.divide(
+                            Calculator.multiply(Calculator.divide(count, endTime - startTime), vo.getUnexistCount()),
+                            3600000) + "h");
+                }
+            }
+            int totalUnScanned = studentService.getUnscannedCountByExam(examId);
+            int totalCount = studentService.getCountByExam(examId);
+            ret.getTotal().setStudentCount(totalCount);
+            ret.getTotal().setUnexistCount(totalUnScanned);
+            ret.getTotal().setProgress(
+                    Calculator.percentage(ret.getTotal().getScannedCount(), ret.getTotal().getStudentCount(), 2));
+            Integer count = batchPaperService.getScanStudentCount(examId, null, startTime, endTime);
+            if (count == null || count == 0) {
+                ret.getTotal().setEstimation("-");
+            } else {
+                ret.getTotal().setEstimation(
+                        Calculator.divide(Calculator.multiply(Calculator.divide(count, endTime - startTime),
+                                ret.getTotal().getUnexistCount()), 3600000) + "h");
+            }
+        }
+        return ret;
+    }
+
 }

+ 245 - 0
src/main/java/cn/com/qmth/scancentral/util/Calculator.java

@@ -0,0 +1,245 @@
+package cn.com.qmth.scancentral.util;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+import org.apache.commons.collections4.CollectionUtils;
+
+import com.qmth.boot.core.exception.StatusException;
+
+/**
+ * 计算器
+ *
+ */
+public class Calculator {
+
+    /**
+     * 加法
+     * 
+     * @param v1
+     * @param v2
+     * @return
+     */
+    public static double add(double v1, double v2) {
+        return add(v1, v2, null);
+
+    }
+
+    /**
+     * 加法 保留指定位小数
+     * 
+     * @param v1
+     * @param v2
+     * @param len
+     * @return
+     */
+    public static double add(double v1, double v2, Integer len) {
+        BigDecimal b1 = BigDecimal.valueOf(v1);
+        BigDecimal b2 = BigDecimal.valueOf(v2);
+        if (len == null) {
+            return b1.add(b2).doubleValue();
+        } else {
+            return b1.add(b2).setScale(len, BigDecimal.ROUND_HALF_UP).doubleValue();
+        }
+
+    }
+
+    /**
+     * 加法 保留指定位小数
+     * 
+     * @param ds
+     * @param len
+     * @return
+     */
+    public static double add(List<Double> ds, int len) {
+        if (CollectionUtils.isEmpty(ds)) {
+            throw new StatusException("数组为空");
+        }
+        BigDecimal ret = BigDecimal.valueOf(0.0);
+        for (Double d : ds) {
+            if (d == null) {
+                throw new StatusException("数组元素为空");
+            }
+            ret = ret.add(BigDecimal.valueOf(d));
+        }
+        return ret.setScale(len, BigDecimal.ROUND_HALF_UP).doubleValue();
+
+    }
+
+    /**
+     * 减法
+     * 
+     * @param v1
+     * @param v2
+     * @return
+     */
+    public static double subtract(double v1, double v2) {
+        return subtract(v1, v2, null);
+
+    }
+
+    /**
+     * 减法 保留指定位小数
+     * 
+     * @param v1
+     * @param v2
+     * @param len
+     * @return
+     */
+    public static double subtract(double v1, double v2, Integer len) {
+        BigDecimal b1 = BigDecimal.valueOf(v1);
+        BigDecimal b2 = BigDecimal.valueOf(v2);
+        if (len == null) {
+            return b1.subtract(b2).doubleValue();
+        } else {
+            return b1.subtract(b2).setScale(len, BigDecimal.ROUND_HALF_UP).doubleValue();
+        }
+
+    }
+
+    /**
+     * 差值绝对值
+     * 
+     * @param v1
+     * @param v2
+     * @param len
+     * @return
+     */
+    public static double absoluteDiff(double v1, double v2, Integer len) {
+        BigDecimal b1 = BigDecimal.valueOf(v1);
+        BigDecimal b2 = BigDecimal.valueOf(v2);
+        if (v1 > v2) {
+            if (len == null) {
+                return b1.subtract(b2).doubleValue();
+            } else {
+                return b1.subtract(b2).setScale(len, BigDecimal.ROUND_HALF_UP).doubleValue();
+            }
+        } else {
+            if (len == null) {
+                return b2.subtract(b1).doubleValue();
+            } else {
+                return b2.subtract(b1).setScale(len, BigDecimal.ROUND_HALF_UP).doubleValue();
+            }
+        }
+
+    }
+
+    /**
+     * 乘法
+     * 
+     * @param v1
+     * @param v2
+     * @return
+     */
+    public static double multiply(double v1, double v2) {
+        return multiply(v1, v2, null);
+
+    }
+
+    /**
+     * 乘法 保留指定位小数
+     * 
+     * @param v1
+     * @param v2
+     * @param len
+     * @return
+     */
+    public static double multiply(double v1, double v2, Integer len) {
+        BigDecimal b1 = BigDecimal.valueOf(v1);
+        BigDecimal b2 = BigDecimal.valueOf(v2);
+        if (len == null) {
+            return b1.multiply(b2).doubleValue();
+        } else {
+            return b1.multiply(b2).setScale(len, BigDecimal.ROUND_HALF_UP).doubleValue();
+        }
+
+    }
+
+    /**
+     * 除法
+     * 
+     * @param v1
+     * @param v2
+     * @param len
+     * @return
+     */
+    public static double divide(double v1, double v2) {
+        return divide(v1, v2, null);
+    }
+
+    /**
+     * 除法 保留指定位小数
+     * 
+     * @param v1
+     * @param v2
+     * @param len
+     * @return
+     */
+    public static double divide(double v1, double v2, Integer len) {
+        BigDecimal b1 = BigDecimal.valueOf(v1);
+        BigDecimal b2 = BigDecimal.valueOf(v2);
+        if (len == null) {
+            return b1.divide(b2).doubleValue();
+        } else {
+            return b1.divide(b2, len, BigDecimal.ROUND_HALF_UP).doubleValue();
+        }
+    }
+
+    public static String divide2String(Double v1, Double v2, Integer len) {
+        if (v1 == null || v2 == null || v2 == 0) {
+            return "-";
+        }
+        BigDecimal b1 = BigDecimal.valueOf(v1);
+        BigDecimal b2 = BigDecimal.valueOf(v2);
+        if (len == null) {
+            return String.valueOf(b1.divide(b2).doubleValue());
+        } else {
+            return String.valueOf(b1.divide(b2, len, BigDecimal.ROUND_HALF_UP).doubleValue());
+        }
+
+    }
+
+    /**
+     * 返回百分比 99.3%
+     * 
+     * @param v1
+     *            分子
+     * @param v2
+     *            分母
+     * @param len
+     *            小数位数
+     * @return
+     */
+    public static String percentage(Double v1, Double v2, Integer len) {
+        if (v1 == null || v2 == null || v2 == 0) {
+            return "-";
+        }
+        BigDecimal b1 = BigDecimal.valueOf(v1);
+        BigDecimal b2 = BigDecimal.valueOf(v2);
+        BigDecimal b3 = BigDecimal.valueOf(100);
+        if (len == null) {
+            return b1.multiply(b3).divide(b2).doubleValue() + "%";
+        } else {
+            return b1.multiply(b3).divide(b2, len, BigDecimal.ROUND_HALF_UP).doubleValue() + "%";
+        }
+
+    }
+
+    public static String percentage(Integer v1, Integer v2, Integer len) {
+        if (v1 == null || v2 == null || v2 == 0) {
+            return "-";
+        }
+        return percentage(v1.doubleValue(), v2.doubleValue(), len);
+    }
+
+    public static String percentage(Integer v1, Integer v2) {
+        if (v1 == null || v2 == null || v2 == 0) {
+            return "-";
+        }
+        return percentage(v1.doubleValue(), v2.doubleValue(), null);
+    }
+
+    public static String percentage(double v1, double v2) {
+        return percentage(v1, v2, null);
+    }
+}

+ 27 - 0
src/main/java/cn/com/qmth/scancentral/vo/subject/ScanProgressVo.java

@@ -0,0 +1,27 @@
+package cn.com.qmth.scancentral.vo.subject;
+
+import java.util.List;
+
+public class ScanProgressVo {
+
+    private SubjectScanProgressVo total;
+
+    private List<SubjectScanProgressVo> subjects;
+
+    public SubjectScanProgressVo getTotal() {
+        return total;
+    }
+
+    public void setTotal(SubjectScanProgressVo total) {
+        this.total = total;
+    }
+
+    public List<SubjectScanProgressVo> getSubjects() {
+        return subjects;
+    }
+
+    public void setSubjects(List<SubjectScanProgressVo> subjects) {
+        this.subjects = subjects;
+    }
+
+}

+ 75 - 0
src/main/java/cn/com/qmth/scancentral/vo/subject/SubjectScanProgressVo.java

@@ -0,0 +1,75 @@
+package cn.com.qmth.scancentral.vo.subject;
+
+public class SubjectScanProgressVo {
+
+    private String subjectCode;
+
+    private String subjectName;
+
+    private String progress;
+
+    private Integer studentCount;
+
+    private Integer unexistCount;
+
+    private Integer scannedCount;
+
+    private String estimation;
+
+    public String getSubjectCode() {
+        return subjectCode;
+    }
+
+    public void setSubjectCode(String subjectCode) {
+        this.subjectCode = subjectCode;
+    }
+
+    public String getSubjectName() {
+        return subjectName;
+    }
+
+    public void setSubjectName(String subjectName) {
+        this.subjectName = subjectName;
+    }
+
+    public String getProgress() {
+        return progress;
+    }
+
+    public void setProgress(String progress) {
+        this.progress = progress;
+    }
+
+    public Integer getStudentCount() {
+        return studentCount;
+    }
+
+    public void setStudentCount(Integer studentCount) {
+        this.studentCount = studentCount;
+    }
+
+    public Integer getUnexistCount() {
+        return unexistCount;
+    }
+
+    public void setUnexistCount(Integer unexistCount) {
+        this.unexistCount = unexistCount;
+    }
+
+    public String getEstimation() {
+        return estimation;
+    }
+
+    public void setEstimation(String estimation) {
+        this.estimation = estimation;
+    }
+
+    public Integer getScannedCount() {
+        return scannedCount;
+    }
+
+    public void setScannedCount(Integer scannedCount) {
+        this.scannedCount = scannedCount;
+    }
+
+}

+ 11 - 0
src/main/resources/mapper/BatchPaperMapper.xml

@@ -8,5 +8,16 @@
         WHERE t.batch_id = #{batchId}
         order by t.student_id
     </select>
+    <select id="getScanStudentCount" resultType="int">
+        SELECT count(DISTINCT t.student_id)
+        FROM sc_batch_paper t
+        inner join sc_student s on t.student_id=s.id
+        WHERE s.exam_id = #{examId} 
+        <if test="subjectCode != null and subjectCode !=''">
+            and s.subject_code=#{subjectCode}
+        </if>
+        and t.create_time&gt;=#{startTime}
+        and t.create_time&lt;=#{endTime}
+    </select>
 
 </mapper>

+ 12 - 0
src/main/resources/mapper/StudentMapper.xml

@@ -512,4 +512,16 @@
                                     WHERE h.student_id = #{id})
         WHERE id = #{id}
     </update>
+    <select id="scanProgress" resultType="cn.com.qmth.scancentral.vo.subject.SubjectScanProgressVo">
+    	select t.subject_code,t.subject_name,
+    	sum(case when t.status='UNEXIST' then 1 else 0 end) unexistCount,
+    	count(1) studentCount
+    	from sc_student t
+    	where t.exam_id=#{examId}
+        <if test="subjectCode != null and subjectCode !=''">
+            and t.subject_code=#{subjectCode}
+        </if>
+        group by t.subject_code
+    </select>
+    
 </mapper>