xiatian 10 kuukautta sitten
vanhempi
commit
d57f9ebc5d
26 muutettua tiedostoa jossa 989 lisäystä ja 375 poistoa
  1. 4 2
      install/mysql/init/stmms_ft.sql
  2. 7 1
      install/mysql/upgrade/1.5.1.sql
  3. 2 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/CheckStudentDao.java
  4. 8 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/ExamSubjectDao.java
  5. 3 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/MarkGroupDao.java
  6. 2 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/CheckStudentService.java
  7. 4 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/ExamSubjectService.java
  8. 2 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/MarkGroupService.java
  9. 5 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/CheckStudentServiceImpl.java
  10. 416 372
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/ExamSubjectServiceImpl.java
  11. 5 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/MarkGroupServiceImpl.java
  12. 44 0
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/basic/OverviewController.java
  13. 194 0
      stmms-web/src/main/webapp/WEB-INF/views/modules/basic/overview.jsp
  14. 293 0
      stmms-web/src/main/webapp/static/overview/css/overview.css
  15. BIN
      stmms-web/src/main/webapp/static/overview/image/btn_link.png
  16. BIN
      stmms-web/src/main/webapp/static/overview/image/done.png
  17. BIN
      stmms-web/src/main/webapp/static/overview/image/guide1.png
  18. BIN
      stmms-web/src/main/webapp/static/overview/image/guide2.png
  19. BIN
      stmms-web/src/main/webapp/static/overview/image/guide3.png
  20. BIN
      stmms-web/src/main/webapp/static/overview/image/guide4.png
  21. BIN
      stmms-web/src/main/webapp/static/overview/image/guide5.png
  22. BIN
      stmms-web/src/main/webapp/static/overview/image/guide6.png
  23. BIN
      stmms-web/src/main/webapp/static/overview/image/guide_bg.png
  24. BIN
      stmms-web/src/main/webapp/static/overview/image/guide_to_bottom.png
  25. BIN
      stmms-web/src/main/webapp/static/overview/image/guide_to_left.png
  26. BIN
      stmms-web/src/main/webapp/static/overview/image/guide_to_right.png

+ 4 - 2
install/mysql/init/stmms_ft.sql

@@ -1309,6 +1309,8 @@ CREATE TABLE `b_role_privilege`
   DEFAULT CHARSET = utf8mb4 COMMENT ='角色权限关联表';
   DEFAULT CHARSET = utf8mb4 COMMENT ='角色权限关联表';
 
 
 LOCK TABLES `b_privilege` WRITE;
 LOCK TABLES `b_privilege` WRITE;
+INSERT INTO `b_privilege` ( `code`, `name`, `parent_code`, `privilege_type`, `privilege_uri`, `seq`,`level`,`icon`)
+VALUES ('overview', '主页导览', 'root_code', 'MENU', '/admin/basic/overview', 5,1,'icon-bookmark');
 INSERT INTO `b_privilege` ( `code`, `name`, `parent_code`, `privilege_type`, `privilege_uri`, `seq`,`level`,`icon`,`i18n`)
 INSERT INTO `b_privilege` ( `code`, `name`, `parent_code`, `privilege_type`, `privilege_uri`, `seq`,`level`,`icon`,`i18n`)
 VALUES ('user_list', '用户管理', 'root_code', 'MENU', '/admin/user/list', 10,1,'icon-user','index.user');
 VALUES ('user_list', '用户管理', 'root_code', 'MENU', '/admin/user/list', 10,1,'icon-user','index.user');
 INSERT INTO `b_privilege` ( `code`, `name`, `parent_code`, `privilege_type`, `privilege_uri`, `seq`,`level`,`icon`,`i18n`)
 INSERT INTO `b_privilege` ( `code`, `name`, `parent_code`, `privilege_type`, `privilege_uri`, `seq`,`level`,`icon`,`i18n`)
@@ -1316,9 +1318,9 @@ VALUES ('exam_list', '考试管理', 'root_code', 'MENU', '/admin/exam/list', 20
 INSERT INTO `b_privilege` ( `code`, `name`, `parent_code`, `privilege_type`, `privilege_uri`, `seq`,`level`,`icon`,`i18n`)
 INSERT INTO `b_privilege` ( `code`, `name`, `parent_code`, `privilege_type`, `privilege_uri`, `seq`,`level`,`icon`,`i18n`)
 VALUES ('exam_student', '考生管理', 'root_code', 'MENU', '/admin/exam/student', 30,1,'icon-user','index.student');
 VALUES ('exam_student', '考生管理', 'root_code', 'MENU', '/admin/exam/student', 30,1,'icon-user','index.student');
 INSERT INTO `b_privilege` ( `code`, `name`, `parent_code`, `privilege_type`, `privilege_uri`, `seq`,`level`,`icon`,`i18n`)
 INSERT INTO `b_privilege` ( `code`, `name`, `parent_code`, `privilege_type`, `privilege_uri`, `seq`,`level`,`icon`,`i18n`)
-VALUES ('exam_paper', '科目管理', 'root_code', 'MENU', '/admin/exam/paper', 40,1,'icon-book','index.paper');
+VALUES ('exam_scan', '扫描进度', 'root_code', 'MENU', '/admin/exam/scan', 40,1,'icon-print','index.scan');
 INSERT INTO `b_privilege` ( `code`, `name`, `parent_code`, `privilege_type`, `privilege_uri`, `seq`,`level`,`icon`,`i18n`)
 INSERT INTO `b_privilege` ( `code`, `name`, `parent_code`, `privilege_type`, `privilege_uri`, `seq`,`level`,`icon`,`i18n`)
-VALUES ('exam_scan', '扫描进度', 'root_code', 'MENU', '/admin/exam/scan', 50,1,'icon-print','index.scan');
+VALUES ('exam_paper', '科目管理', 'root_code', 'MENU', '/admin/exam/paper', 50,1,'icon-book','index.paper');
 INSERT INTO `b_privilege` ( `code`, `name`, `parent_code`, `privilege_type`, `privilege_uri`, `seq`,`level`,`icon`,`i18n`)
 INSERT INTO `b_privilege` ( `code`, `name`, `parent_code`, `privilege_type`, `privilege_uri`, `seq`,`level`,`icon`,`i18n`)
 VALUES ('exam_mark', '评卷管理', 'root_code', 'MENU', '/admin/basic/role/info/sub/page', 60,1,'icon-pencil','index.mark');
 VALUES ('exam_mark', '评卷管理', 'root_code', 'MENU', '/admin/basic/role/info/sub/page', 60,1,'icon-pencil','index.mark');
 INSERT INTO `b_privilege` ( `code`, `name`, `parent_code`, `privilege_type`,`privilege_uri`,`level`, `seq`)
 INSERT INTO `b_privilege` ( `code`, `name`, `parent_code`, `privilege_type`,`privilege_uri`,`level`, `seq`)

+ 7 - 1
install/mysql/upgrade/1.5.1.sql

@@ -8,11 +8,17 @@ ALTER TABLE eb_marker ADD COLUMN `stdev_score_na`  double      DEFAULT NULL COMM
 
 
 ALTER TABLE eb_exam ADD COLUMN `inspect_round_limit`   	tinyint(1)  NOT NULL DEFAULT 1 COMMENT '全卷复核进度100%时才能再次复核';
 ALTER TABLE eb_exam ADD COLUMN `inspect_round_limit`   	tinyint(1)  NOT NULL DEFAULT 1 COMMENT '全卷复核进度100%时才能再次复核';
 
 
+update b_privilege set seq=50 where code='exam_paper';
+update b_privilege set seq=40 where code='exam_scan';
+
 
 
 delete from b_privilege t where t.code in ('exam_report_subject','exam_report_subject_range');
 delete from b_privilege t where t.code in ('exam_report_subject','exam_report_subject_range');
 delete from b_role_privilege t where t.privilege_code in ('exam_report_subject','exam_report_subject_range');
 delete from b_role_privilege t where t.privilege_code in ('exam_report_subject','exam_report_subject_range');
 delete from b_role_privilege t where t.privilege_code in ('exam_mark-group-add','exam_mark-group-edit','exam_mark-group-reset_edit','exam_mark-group-delete');
 delete from b_role_privilege t where t.privilege_code in ('exam_mark-group-add','exam_mark-group-edit','exam_mark-group-reset_edit','exam_mark-group-delete');
 
 
+INSERT INTO `b_privilege` ( `code`, `name`, `parent_code`, `privilege_type`, `privilege_uri`, `seq`,`level`,`icon`)
+VALUES ('overview', '主页导览', 'root_code', 'MENU', '/admin/basic/overview', 5,1,'icon-bookmark');
+
 INSERT INTO `b_privilege` ( `code`, `name`, `parent_code`, `privilege_type`, `privilege_uri`, `seq`,`level`,`icon`,`i18n`)
 INSERT INTO `b_privilege` ( `code`, `name`, `parent_code`, `privilege_type`, `privilege_uri`, `seq`,`level`,`icon`,`i18n`)
 VALUES ('exam_report_subject', '科目分析', 'root_code', 'MENU', '/admin/basic/role/info/sub/page', 110,1,'icon-asterisk','index.report.subject');
 VALUES ('exam_report_subject', '科目分析', 'root_code', 'MENU', '/admin/basic/role/info/sub/page', 110,1,'icon-asterisk','index.report.subject');
 INSERT INTO `b_privilege` ( `code`, `name`, `parent_code`, `privilege_type`, `privilege_uri`, `seq`,`level`)
 INSERT INTO `b_privilege` ( `code`, `name`, `parent_code`, `privilege_type`, `privilege_uri`, `seq`,`level`)
@@ -34,7 +40,7 @@ VALUES ('exam_report_subject-group', '大题分析', 'exam_report_subject', 'PAG
 
 
 INSERT INTO b_role_privilege (`school_id`, `role_code`, `privilege_code`,`enable`)
 INSERT INTO b_role_privilege (`school_id`, `role_code`, `privilege_code`,`enable`)
 SELECT s.id,'SCHOOL_ADMIN',p.`code`,1 from b_privilege p join b_school s   
 SELECT s.id,'SCHOOL_ADMIN',p.`code`,1 from b_privilege p join b_school s   
-where p.`code` in('exam_report_subject','exam_report_subject-total','exam_report_subject-range','exam_report_subject-college',
+where p.`code` in('overview','exam_report_subject','exam_report_subject-total','exam_report_subject-range','exam_report_subject-college',
 'exam_report_subject-teacher','exam_report_subject-class'
 'exam_report_subject-teacher','exam_report_subject-class'
 ,'exam_report_subject-objective_question','exam_report_subject-subjective_question','exam_report_subject-group');
 ,'exam_report_subject-objective_question','exam_report_subject-subjective_question','exam_report_subject-group');
 
 

+ 2 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/CheckStudentDao.java

@@ -20,6 +20,8 @@ public interface CheckStudentDao extends PagingAndSortingRepository<CheckStudent
     void deleteByStudentId(int examId);
     void deleteByStudentId(int examId);
 
 
     long countByExamIdAndChecked(int examId, boolean checked);
     long countByExamIdAndChecked(int examId, boolean checked);
+    
+    long countByExamIdAndCheckedAndType(int examId, boolean checked,CheckType type);
 
 
     long countByExamIdAndSubjectCodeAndChecked(int examId, String subjectCode, boolean checked);
     long countByExamIdAndSubjectCodeAndChecked(int examId, String subjectCode, boolean checked);
 
 

+ 8 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/ExamSubjectDao.java

@@ -101,4 +101,12 @@ public interface ExamSubjectDao
 
 
     @Query("select s from ExamSubject s where s.pk.examId=?1 and s.objectiveScore>?2")
     @Query("select s from ExamSubject s where s.pk.examId=?1 and s.objectiveScore>?2")
     List<ExamSubject> listObjectiveScore(Integer examId, double objectiveScoreGt);
     List<ExamSubject> listObjectiveScore(Integer examId, double objectiveScoreGt);
+    
+    @Query(value = "select count(1) from eb_exam_subject t "
+    		+ "where es.exam_id =?1  and t.total_score=0", nativeQuery = true)
+    long getZeroScoreCount(Integer examId);
+
+    @Query(value = "select count(*) from eb_exam_subject t left join eb_mark_group f on t.exam_id=f.exam_id and t.subject_code=f.subject_code "
+    		+ "where es.exam_id =?1  and t.subjective_score is not null and t.subjective_score>0 and f.exam_id is null", nativeQuery = true)
+	public long getNoGroupCount(Integer id);
 }
 }

+ 3 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/MarkGroupDao.java

@@ -28,6 +28,9 @@ public interface MarkGroupDao
 
 
     @Query("select count(q) from MarkGroup q where q.pk.examId=?1 and q.pk.subjectCode=?2 and q.status in (?3)")
     @Query("select count(q) from MarkGroup q where q.pk.examId=?1 and q.pk.subjectCode=?2 and q.status in (?3)")
     long countByExamIdAndSubjectCodeAndStatus(Integer examId, String subjectCode, MarkStatus... status);
     long countByExamIdAndSubjectCodeAndStatus(Integer examId, String subjectCode, MarkStatus... status);
+    
+    @Query("select count(q) from MarkGroup q where q.pk.examId=?1  and q.status in (?2)")
+    long countByExamIdAndStatus(Integer examId, MarkStatus... status);
 
 
     @Query("select count(q) from MarkGroup q where q.pk.examId=?1 and q.pk.subjectCode=?2 "
     @Query("select count(q) from MarkGroup q where q.pk.examId=?1 and q.pk.subjectCode=?2 "
             + "and q.pk.number=?3 and q.status in (?4)")
             + "and q.pk.number=?3 and q.status in (?4)")

+ 2 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/CheckStudentService.java

@@ -27,4 +27,6 @@ public interface CheckStudentService {
     List<CheckStudent> findByExamIdAndSubjectCodeAndCheckedAndType(int examId, String subjectCode, boolean checked,
     List<CheckStudent> findByExamIdAndSubjectCodeAndCheckedAndType(int examId, String subjectCode, boolean checked,
             CheckType type);
             CheckType type);
 
 
+	long countByExamIdAndCheckedAndType(int examId, boolean checked, CheckType type);
+
 }
 }

+ 4 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/ExamSubjectService.java

@@ -62,4 +62,8 @@ public interface ExamSubjectService {
     List<ExamSubject> listObjectiveScore(Integer examId, double objectiveScoreGt);
     List<ExamSubject> listObjectiveScore(Integer examId, double objectiveScoreGt);
 
 
 	String split(Integer schoolId, Integer examId, List<SubjectSplit> list);
 	String split(Integer schoolId, Integer examId, List<SubjectSplit> list);
+
+	Boolean checkSubjectForExport(Integer examId);
+	
+	Boolean checkSubjectAbsentForExport(Integer examId);
 }
 }

+ 2 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/MarkGroupService.java

@@ -49,6 +49,8 @@ public interface MarkGroupService {
     List<MarkGroup> findByExamAndSubjectAndStatus(Integer examId, String subjectCode, MarkStatus... status);
     List<MarkGroup> findByExamAndSubjectAndStatus(Integer examId, String subjectCode, MarkStatus... status);
 
 
     long countByExamAndSubjectAndStatus(Integer examId, String subjectCode, MarkStatus... status);
     long countByExamAndSubjectAndStatus(Integer examId, String subjectCode, MarkStatus... status);
+    
+    long countByExamAndStatus(Integer examId, MarkStatus... status);
 
 
     boolean validateStatus(Integer examId, String subjectCode, Integer number, MarkStatus... status);
     boolean validateStatus(Integer examId, String subjectCode, Integer number, MarkStatus... status);
 
 

+ 5 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/CheckStudentServiceImpl.java

@@ -53,6 +53,11 @@ public class CheckStudentServiceImpl extends BaseQueryService<CheckStudent> impl
     public long countByExamIdAndChecked(int examId, boolean checked) {
     public long countByExamIdAndChecked(int examId, boolean checked) {
         return checkStudentDao.countByExamIdAndChecked(examId, checked);
         return checkStudentDao.countByExamIdAndChecked(examId, checked);
     }
     }
+    
+    @Override
+    public long countByExamIdAndCheckedAndType(int examId, boolean checked,CheckType type) {
+        return checkStudentDao.countByExamIdAndCheckedAndType(examId, checked,type);
+    }
 
 
     @Override
     @Override
     public CheckStudentSearchQuery findByQuery(final CheckStudentSearchQuery query) {
     public CheckStudentSearchQuery findByQuery(final CheckStudentSearchQuery query) {

+ 416 - 372
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/ExamSubjectServiceImpl.java

@@ -32,6 +32,7 @@ import cn.com.qmth.stmms.biz.exam.model.ExamSubject;
 import cn.com.qmth.stmms.biz.exam.model.MarkGroup;
 import cn.com.qmth.stmms.biz.exam.model.MarkGroup;
 import cn.com.qmth.stmms.biz.exam.query.ExamStudentSearchQuery;
 import cn.com.qmth.stmms.biz.exam.query.ExamStudentSearchQuery;
 import cn.com.qmth.stmms.biz.exam.service.CheckStudentService;
 import cn.com.qmth.stmms.biz.exam.service.CheckStudentService;
+import cn.com.qmth.stmms.biz.exam.service.ExamService;
 import cn.com.qmth.stmms.biz.exam.service.ExamStudentService;
 import cn.com.qmth.stmms.biz.exam.service.ExamStudentService;
 import cn.com.qmth.stmms.biz.exam.service.ExamSubjectService;
 import cn.com.qmth.stmms.biz.exam.service.ExamSubjectService;
 import cn.com.qmth.stmms.biz.exam.service.MarkGroupService;
 import cn.com.qmth.stmms.biz.exam.service.MarkGroupService;
@@ -45,387 +46,430 @@ import cn.com.qmth.stmms.common.enums.MarkStatus;
 @Service("examSubjectService")
 @Service("examSubjectService")
 public class ExamSubjectServiceImpl extends BaseQueryService<ExamSubject> implements ExamSubjectService {
 public class ExamSubjectServiceImpl extends BaseQueryService<ExamSubject> implements ExamSubjectService {
 
 
-    @Autowired
-    private ExamSubjectDao subjectDao;
-
-    @Autowired
-    private ExamStudentDao examStudentDao;
-
-    @PersistenceContext
-    private EntityManager entityManager;
-
-    @Autowired
-    private MarkGroupService groupService;
-
-    @Autowired
-    private ExamStudentService studentService;
-
-    @Autowired
-    private CheckStudentService checkStudentService;
-    
-    @Autowired
-    private MarkGroupService markGroupService;
-
-    @Transactional
-    @Override
-    // @CachePut(value = "exam_subject_cache", key =
-    // "T(String).valueOf(#subject.examId)+'-'+#subject.code", condition =
-    // "#subject!=null && #subject.examId!=null && #subject.code!=null")
-    public ExamSubject save(ExamSubject subject) {
-        return subjectDao.save(subject);
-    }
-
-    @Override
-    // @Cacheable(value = "exam_subject_cache", key =
-    // "T(String).valueOf(#examId)+'-'+#code", condition =
-    // "#examId>0 && #code!=null")
-    public ExamSubject find(int examId, String code) {
-        return subjectDao.findByExamIdAndCode(examId, code);
-    }
-
-    @Override
-    public List<ExamSubject> list(int examId) {
-        return subjectDao.findByExamId(examId);
-    }
-
-    @Override
-    public List<ExamSubject> list(int examId, Set<String> codes) {
-        return subjectDao.findByExamIdAndSubjectCodeIn(examId, codes);
-    }
-
-    @Override
-    public List<String> listLevel(int examId) {
-        return subjectDao.findDistinctLevel(examId);
-    }
-
-    @Override
-    public List<String> listCategory(int examId) {
-        return subjectDao.findDistinctCategory(examId);
-    }
-
-    @Override
-    public List<ExamSubject> list(int examId, int uploadCountGt) {
-        return subjectDao.findByExamIdAndUploadCountGt(examId, uploadCountGt);
-    }
-
-    @Override
-    public long count(int examId) {
-        return subjectDao.countByExamId(examId);
-    }
-
-    @Override
-    public ExamSubjectSearchQuery findByQuery(ExamSubjectSearchQuery query) {
-        checkQuery(query);
-        Page<ExamSubject> result = subjectDao.findAll(buildSpecification(query), query);
-        fillResult(result, query);
-        return query;
-    }
-
-    @Override
-    public long countByQuery(ExamSubjectSearchQuery query) {
-        return subjectDao.count(buildSpecification(query));
-    }
-
-    @Transactional
-    @Override
-    // @CacheEvict(value = "exam_subject_cache", beforeInvocation = true,
-    // allEntries = true)
-    public void delete(ExamSubject markSubject) {
-        subjectDao.delete(markSubject);
-    }
-
-    @Transactional
-    @Override
-    // @CacheEvict(value = "exam_subject_cache", beforeInvocation = true,
-    // allEntries = true)
-    public void deleteByExamId(int examId) {
-        subjectDao.deleteByExamId(examId);
-    }
-
-    @Transactional
-    @Override
-    // @CacheEvict(value = "exam_subject_cache", beforeInvocation = true,
-    // allEntries = true)
-    public void updateTotalScore(int examId) {
-        subjectDao.updateTotalScoreByExamId(examId);
-    }
-
-    @Transactional
-    @Override
-    // @CacheEvict(value = "exam_subject_cache", beforeInvocation = true,
-    // allEntries = true)
-    public void updateScore(int examId, String code, boolean objective, double score) {
-        if (objective) {
-            subjectDao.updateObjectiveScore(examId, code, score);
-        } else {
-            subjectDao.updateSubjectiveScore(examId, code, score);
-        }
-        subjectDao.updateTotalScoreByExamIdAndCode(examId, code);
-    }
-
-    private Specification<ExamSubject> buildSpecification(final ExamSubjectSearchQuery query) {
-        return new Specification<ExamSubject>() {
-
-            @Override
-            public Predicate toPredicate(Root<ExamSubject> root, CriteriaQuery<?> cQuery, CriteriaBuilder cb) {
-                List<Predicate> predicates = new LinkedList<Predicate>();
-                if (query.getExamId() > 0) {
-                    predicates.add(cb.equal(root.get("pk").get("examId"), query.getExamId()));
-                }
-                if (StringUtils.isNotEmpty(query.getCode())) {
-                    predicates.add(cb.equal(root.get("pk").get("code"), query.getCode()));
-                }
-                if (StringUtils.isNotBlank(query.getLevel())) {
-                    predicates.add(cb.equal(root.get("level"), query.getLevel()));
-                }
-                if (StringUtils.isNotBlank(query.getCategory())) {
-                    predicates.add(cb.equal(root.get("category"), query.getCategory()));
-                }
-                if (query.getTotalScore() != null) {
-                    predicates.add(cb.equal(root.get("totalScore"), query.getTotalScore()));
-                }
-                if (query.getTotalScoreNotEqual() != null) {
-                    predicates.add(cb.notEqual(root.get("totalScore"), query.getTotalScoreNotEqual()));
-                }
-                if (query.getSubjectiveScoreNotEqual() != null) {
-                    predicates.add(cb.notEqual(root.get("subjectiveScore"), query.getSubjectiveScoreNotEqual()));
-                }
-                if (query.getUploadCountGt() != null) {
-                    predicates.add(cb.gt(root.get("uploadCount").as(Integer.class), query.getUploadCountGt()));
-                }
-                if (query.getUploadCountEqual() != null) {
-                    predicates.add(cb.equal(root.get("uploadCount").as(Integer.class), query.getUploadCountEqual()));
-                }
-                if (query.getSelective() != null) {
-                    predicates.add(cb.equal(root.get("selective"), query.getSelective()));
-                }
-                if (StringUtils.isNotBlank(query.getCodeIn())) {
-                    String[] list = query.getCodeIn().split(",");
-                    if (list.length > 0) {
-                        Predicate[] sub = new Predicate[list.length];
-                        for (int i = 0; i < list.length; i++) {
-                            sub[i] = cb.equal(root.get("pk").get("code"), list[i]);
-                        }
-                        predicates.add(cb.or(sub));
-                    }
-                }
-                if (StringUtils.isNotBlank(query.getCodeNotIn())) {
-                    String[] list = query.getCodeNotIn().split(",");
-                    if (list.length > 0) {
-                        Predicate[] sub = new Predicate[list.length];
-                        for (int i = 0; i < list.length; i++) {
-                            sub[i] = cb.notEqual(root.get("pk").get("code"), list[i]);
-                        }
-                        predicates.add(cb.and(sub));
-                    }
-                }
-                return predicates.isEmpty() ? cb.conjunction()
-                        : cb.and(predicates.toArray(new Predicate[predicates.size()]));
-            }
-        };
-    }
-
-    @Override
-    @Transactional
-    public void updateUploadCount(Integer examId, String subjectCode, int count) {
-        subjectDao.updateUploadCount(examId, subjectCode, count);
-    }
-
-    @Override
-    public List<ExamSubject> listSubjectiveScore(int examId, double subjectiveScore) {
-        return subjectDao.listSubjectiveScore(examId, subjectiveScore);
-    }
-
-    @Override
-    @Transactional
-    public void updateSliceConfig(Integer examId, String subjectCode, List<PictureConfigItem> configList) {
-        subjectDao.updateSliceConfig(examId, subjectCode,
-                configList != null ? StringUtils.join(configList, PictureConfigItem.DB_ITEM_JOINER) : "");
-    }
-
-    @Transactional
-    @Override
-    public void updateTrialCount(int examId, String subjectCode, int trialCount) {
-        subjectDao.updateTrialCount(examId, subjectCode, trialCount);
-    }
-
-    @Override
-    public int findMaxInspectRound(int examId, Set<String> subjectCodes) {
-        StringBuilder sql = new StringBuilder("select max(s.inspect_round) from eb_exam_subject s ");
-        sql.append(" where s.exam_id=" + examId + " and s.code in ('" + StringUtils.join(subjectCodes, "','") + "')");
-        Query countQuery = entityManager.createNativeQuery(sql.toString());
-        Object singleResult = countQuery.getResultList().get(0);
-        Integer count = singleResult == null ? 0 : Integer.valueOf(singleResult.toString());
-        return count;
-    }
-
-    @Transactional
-    @Override
-    public void nextInspectRound(int examId, String subjectCode) {
-        subjectDao.nextInspectRound(examId, subjectCode);
-        examStudentDao.cancelInspect(examId, subjectCode, false, true);
-    }
-
-    @Transactional
-    @Override
-    public void updateSelective(int examId, String subjectCode, boolean selective) {
-        subjectDao.updateSelective(examId, subjectCode, selective);
-    }
-
-    @Override
-    public String enableExport(Exam exam, String subjectCode) {
-        ExamSubject subject = find(exam.getId(), subjectCode);
-        if (subject == null) {
-            return subjectCode + "该科目不存在";
-        }
-        List<MarkGroup> groups = groupService.findByExamAndSubjectAndStatus(exam.getId(), subjectCode,
-                MarkStatus.FORMAL, MarkStatus.TRIAL);
-        if (groups != null && !groups.isEmpty()) {
-            return subjectCode + "评卷未完成";
-        }
-        if (ExamType.MULTI_MEDIA.equals(exam.getType())) {
-            return null;
-        }
-        if (DoubleUtil.sum(subject.getObjectiveScore(), subject.getSubjectiveScore()) == 0) {
-            return subjectCode + "科目总分为0";
-        }
-        long groupCount = groupService.countByExamAndSubject(exam.getId(), subjectCode);
-        if (subject.getSubjectiveScore() != null && subject.getSubjectiveScore() > 0 && groupCount == 0) {
-            return subjectCode + "未设置评卷分组";
-        }
-        if (checkStudentService.countByExamIdAndSubjectCodeAndChecked(exam.getId(), subjectCode, false) > 0) {
-            return subjectCode + "人工确认未完成";
-        }
-        ExamStudentSearchQuery query = new ExamStudentSearchQuery();
-        query.setExamId(exam.getId());
-        query.setUpload(false);
-        query.setManualAbsent(false);
-        query.setSubjectCode(subjectCode);
-        if (studentService.countByQuery(query) > 0) {
-            StringBuilder builder = new StringBuilder(subjectCode + "未上传考生必须人工指定缺考");
-            query.setPageSize(Integer.MAX_VALUE);
-            query = studentService.findByQuery(query);
-            for (ExamStudent s : query.getResult()) {
-                builder.append("," + s.getExamNumber());
-            }
-            return builder.toString();
-        }
-        query.setUpload(true);
-        query.setManualAbsent(true);
-        if (studentService.countByQuery(query) > 0) {
-            StringBuilder builder = new StringBuilder(subjectCode + "已上传考生有人工指定缺考");
-            query.setPageSize(Integer.MAX_VALUE);
-            query = studentService.findByQuery(query);
-            for (ExamStudent s : query.getResult()) {
-                builder.append("," + s.getExamNumber());
-            }
-            return builder.toString();
-        }
-        return null;
-    }
-
-    @Override
-    public List<Double> distinctTotalScore(int examId) {
-        return subjectDao.distinctTotalScore(examId);
-    }
-
-    @Transactional
-    @Override
-    public void resetInspect(int examId, String subjectCode) {
-        subjectDao.resetInspect(examId, subjectCode);
-    }
-
-    @Override
-    public List<ExamSubject> listObjectiveScore(Integer examId, double objectiveScoreGt) {
-        return subjectDao.listObjectiveScore(examId, objectiveScoreGt);
-    }
-
-    @Transactional
+	@Autowired
+	private ExamSubjectDao subjectDao;
+	@Autowired
+	private ExamService examService;
+	@Autowired
+	private ExamStudentDao examStudentDao;
+
+	@PersistenceContext
+	private EntityManager entityManager;
+
+	@Autowired
+	private MarkGroupService groupService;
+
+	@Autowired
+	private ExamStudentService studentService;
+
+	@Autowired
+	private CheckStudentService checkStudentService;
+
+	@Autowired
+	private MarkGroupService markGroupService;
+
+	@Transactional
+	@Override
+	// @CachePut(value = "exam_subject_cache", key =
+	// "T(String).valueOf(#subject.examId)+'-'+#subject.code", condition =
+	// "#subject!=null && #subject.examId!=null && #subject.code!=null")
+	public ExamSubject save(ExamSubject subject) {
+		return subjectDao.save(subject);
+	}
+
+	@Override
+	// @Cacheable(value = "exam_subject_cache", key =
+	// "T(String).valueOf(#examId)+'-'+#code", condition =
+	// "#examId>0 && #code!=null")
+	public ExamSubject find(int examId, String code) {
+		return subjectDao.findByExamIdAndCode(examId, code);
+	}
+
+	@Override
+	public List<ExamSubject> list(int examId) {
+		return subjectDao.findByExamId(examId);
+	}
+
+	@Override
+	public List<ExamSubject> list(int examId, Set<String> codes) {
+		return subjectDao.findByExamIdAndSubjectCodeIn(examId, codes);
+	}
+
+	@Override
+	public List<String> listLevel(int examId) {
+		return subjectDao.findDistinctLevel(examId);
+	}
+
+	@Override
+	public List<String> listCategory(int examId) {
+		return subjectDao.findDistinctCategory(examId);
+	}
+
+	@Override
+	public List<ExamSubject> list(int examId, int uploadCountGt) {
+		return subjectDao.findByExamIdAndUploadCountGt(examId, uploadCountGt);
+	}
+
+	@Override
+	public long count(int examId) {
+		return subjectDao.countByExamId(examId);
+	}
+
+	@Override
+	public ExamSubjectSearchQuery findByQuery(ExamSubjectSearchQuery query) {
+		checkQuery(query);
+		Page<ExamSubject> result = subjectDao.findAll(buildSpecification(query), query);
+		fillResult(result, query);
+		return query;
+	}
+
+	@Override
+	public long countByQuery(ExamSubjectSearchQuery query) {
+		return subjectDao.count(buildSpecification(query));
+	}
+
+	@Transactional
+	@Override
+	// @CacheEvict(value = "exam_subject_cache", beforeInvocation = true,
+	// allEntries = true)
+	public void delete(ExamSubject markSubject) {
+		subjectDao.delete(markSubject);
+	}
+
+	@Transactional
+	@Override
+	// @CacheEvict(value = "exam_subject_cache", beforeInvocation = true,
+	// allEntries = true)
+	public void deleteByExamId(int examId) {
+		subjectDao.deleteByExamId(examId);
+	}
+
+	@Transactional
+	@Override
+	// @CacheEvict(value = "exam_subject_cache", beforeInvocation = true,
+	// allEntries = true)
+	public void updateTotalScore(int examId) {
+		subjectDao.updateTotalScoreByExamId(examId);
+	}
+
+	@Transactional
+	@Override
+	// @CacheEvict(value = "exam_subject_cache", beforeInvocation = true,
+	// allEntries = true)
+	public void updateScore(int examId, String code, boolean objective, double score) {
+		if (objective) {
+			subjectDao.updateObjectiveScore(examId, code, score);
+		} else {
+			subjectDao.updateSubjectiveScore(examId, code, score);
+		}
+		subjectDao.updateTotalScoreByExamIdAndCode(examId, code);
+	}
+
+	private Specification<ExamSubject> buildSpecification(final ExamSubjectSearchQuery query) {
+		return new Specification<ExamSubject>() {
+
+			@Override
+			public Predicate toPredicate(Root<ExamSubject> root, CriteriaQuery<?> cQuery, CriteriaBuilder cb) {
+				List<Predicate> predicates = new LinkedList<Predicate>();
+				if (query.getExamId() > 0) {
+					predicates.add(cb.equal(root.get("pk").get("examId"), query.getExamId()));
+				}
+				if (StringUtils.isNotEmpty(query.getCode())) {
+					predicates.add(cb.equal(root.get("pk").get("code"), query.getCode()));
+				}
+				if (StringUtils.isNotBlank(query.getLevel())) {
+					predicates.add(cb.equal(root.get("level"), query.getLevel()));
+				}
+				if (StringUtils.isNotBlank(query.getCategory())) {
+					predicates.add(cb.equal(root.get("category"), query.getCategory()));
+				}
+				if (query.getTotalScore() != null) {
+					predicates.add(cb.equal(root.get("totalScore"), query.getTotalScore()));
+				}
+				if (query.getTotalScoreNotEqual() != null) {
+					predicates.add(cb.notEqual(root.get("totalScore"), query.getTotalScoreNotEqual()));
+				}
+				if (query.getSubjectiveScoreNotEqual() != null) {
+					predicates.add(cb.notEqual(root.get("subjectiveScore"), query.getSubjectiveScoreNotEqual()));
+				}
+				if (query.getUploadCountGt() != null) {
+					predicates.add(cb.gt(root.get("uploadCount").as(Integer.class), query.getUploadCountGt()));
+				}
+				if (query.getUploadCountEqual() != null) {
+					predicates.add(cb.equal(root.get("uploadCount").as(Integer.class), query.getUploadCountEqual()));
+				}
+				if (query.getSelective() != null) {
+					predicates.add(cb.equal(root.get("selective"), query.getSelective()));
+				}
+				if (StringUtils.isNotBlank(query.getCodeIn())) {
+					String[] list = query.getCodeIn().split(",");
+					if (list.length > 0) {
+						Predicate[] sub = new Predicate[list.length];
+						for (int i = 0; i < list.length; i++) {
+							sub[i] = cb.equal(root.get("pk").get("code"), list[i]);
+						}
+						predicates.add(cb.or(sub));
+					}
+				}
+				if (StringUtils.isNotBlank(query.getCodeNotIn())) {
+					String[] list = query.getCodeNotIn().split(",");
+					if (list.length > 0) {
+						Predicate[] sub = new Predicate[list.length];
+						for (int i = 0; i < list.length; i++) {
+							sub[i] = cb.notEqual(root.get("pk").get("code"), list[i]);
+						}
+						predicates.add(cb.and(sub));
+					}
+				}
+				return predicates.isEmpty() ? cb.conjunction()
+						: cb.and(predicates.toArray(new Predicate[predicates.size()]));
+			}
+		};
+	}
+
+	@Override
+	@Transactional
+	public void updateUploadCount(Integer examId, String subjectCode, int count) {
+		subjectDao.updateUploadCount(examId, subjectCode, count);
+	}
+
+	@Override
+	public List<ExamSubject> listSubjectiveScore(int examId, double subjectiveScore) {
+		return subjectDao.listSubjectiveScore(examId, subjectiveScore);
+	}
+
+	@Override
+	@Transactional
+	public void updateSliceConfig(Integer examId, String subjectCode, List<PictureConfigItem> configList) {
+		subjectDao.updateSliceConfig(examId, subjectCode,
+				configList != null ? StringUtils.join(configList, PictureConfigItem.DB_ITEM_JOINER) : "");
+	}
+
+	@Transactional
+	@Override
+	public void updateTrialCount(int examId, String subjectCode, int trialCount) {
+		subjectDao.updateTrialCount(examId, subjectCode, trialCount);
+	}
+
+	@Override
+	public int findMaxInspectRound(int examId, Set<String> subjectCodes) {
+		StringBuilder sql = new StringBuilder("select max(s.inspect_round) from eb_exam_subject s ");
+		sql.append(" where s.exam_id=" + examId + " and s.code in ('" + StringUtils.join(subjectCodes, "','") + "')");
+		Query countQuery = entityManager.createNativeQuery(sql.toString());
+		Object singleResult = countQuery.getResultList().get(0);
+		Integer count = singleResult == null ? 0 : Integer.valueOf(singleResult.toString());
+		return count;
+	}
+
+	@Transactional
+	@Override
+	public void nextInspectRound(int examId, String subjectCode) {
+		subjectDao.nextInspectRound(examId, subjectCode);
+		examStudentDao.cancelInspect(examId, subjectCode, false, true);
+	}
+
+	@Transactional
+	@Override
+	public void updateSelective(int examId, String subjectCode, boolean selective) {
+		subjectDao.updateSelective(examId, subjectCode, selective);
+	}
+
+	@Override
+	public String enableExport(Exam exam, String subjectCode) {
+		ExamSubject subject = find(exam.getId(), subjectCode);
+		if (subject == null) {
+			return subjectCode + "该科目不存在";
+		}
+		List<MarkGroup> groups = groupService.findByExamAndSubjectAndStatus(exam.getId(), subjectCode,
+				MarkStatus.FORMAL, MarkStatus.TRIAL);
+		if (groups != null && !groups.isEmpty()) {
+			return subjectCode + "评卷未完成";
+		}
+		if (ExamType.MULTI_MEDIA.equals(exam.getType())) {
+			return null;
+		}
+		if (DoubleUtil.sum(subject.getObjectiveScore(), subject.getSubjectiveScore()) == 0) {
+			return subjectCode + "科目总分为0";
+		}
+		long groupCount = groupService.countByExamAndSubject(exam.getId(), subjectCode);
+		if (subject.getSubjectiveScore() != null && subject.getSubjectiveScore() > 0 && groupCount == 0) {
+			return subjectCode + "未设置评卷分组";
+		}
+		if (checkStudentService.countByExamIdAndSubjectCodeAndChecked(exam.getId(), subjectCode, false) > 0) {
+			return subjectCode + "人工确认未完成";
+		}
+		ExamStudentSearchQuery query = new ExamStudentSearchQuery();
+		query.setExamId(exam.getId());
+		query.setUpload(false);
+		query.setManualAbsent(false);
+		query.setSubjectCode(subjectCode);
+		if (studentService.countByQuery(query) > 0) {
+			StringBuilder builder = new StringBuilder(subjectCode + "未上传考生必须人工指定缺考");
+			query.setPageSize(Integer.MAX_VALUE);
+			query = studentService.findByQuery(query);
+			for (ExamStudent s : query.getResult()) {
+				builder.append("," + s.getExamNumber());
+			}
+			return builder.toString();
+		}
+		query.setUpload(true);
+		query.setManualAbsent(true);
+		if (studentService.countByQuery(query) > 0) {
+			StringBuilder builder = new StringBuilder(subjectCode + "已上传考生有人工指定缺考");
+			query.setPageSize(Integer.MAX_VALUE);
+			query = studentService.findByQuery(query);
+			for (ExamStudent s : query.getResult()) {
+				builder.append("," + s.getExamNumber());
+			}
+			return builder.toString();
+		}
+		return null;
+	}
+
+	@Override
+	public Boolean checkSubjectAbsentForExport(Integer examId) {
+		ExamStudentSearchQuery query = new ExamStudentSearchQuery();
+		query.setExamId(examId);
+		query.setUpload(false);
+		query.setManualAbsent(false);
+		if (studentService.countByQuery(query) > 0) {
+			return false;
+		}
+		query.setUpload(true);
+		query.setManualAbsent(true);
+		if (studentService.countByQuery(query) > 0) {
+			return false;
+		}
+		return true;
+	}
+	@Override
+	public Boolean checkSubjectForExport(Integer examId) {
+		Exam exam=examService.findById(examId);
+		if(exam==null) {
+			return false;
+		}
+		long groups = groupService.countByExamAndStatus(examId, MarkStatus.FORMAL, MarkStatus.TRIAL);
+		if (groups>0) {
+			return false;
+		}
+		if (ExamType.MULTI_MEDIA.equals(exam.getType())) {
+			return true;
+		}
+		if (subjectDao.getZeroScoreCount(examId)>0) {
+			return false;
+		}
+		long noGroupCount = subjectDao.getNoGroupCount(exam.getId());
+		if (noGroupCount>0) {
+			return false;
+		}
+		
+		return true;
+	}
+
+	@Override
+	public List<Double> distinctTotalScore(int examId) {
+		return subjectDao.distinctTotalScore(examId);
+	}
+
+	@Transactional
+	@Override
+	public void resetInspect(int examId, String subjectCode) {
+		subjectDao.resetInspect(examId, subjectCode);
+	}
+
+	@Override
+	public List<ExamSubject> listObjectiveScore(Integer examId, double objectiveScoreGt) {
+		return subjectDao.listObjectiveScore(examId, objectiveScoreGt);
+	}
+
+	@Transactional
 	@Override
 	@Override
 	public String split(Integer schoolId, Integer examId, List<SubjectSplit> list) {
 	public String split(Integer schoolId, Integer examId, List<SubjectSplit> list) {
-    	StringBuilder err=new StringBuilder();
-    	if(CollectionUtils.isEmpty(list)) {
-    		err.append("Excel中没有数据");
-    		return err.toString();
-    	}
-    	int index=0;
-    	for(SubjectSplit vo:list) {
-    		index++;
-    		StringBuilder line=new StringBuilder();
-    		if(StringUtils.isBlank(vo.getExamNumber())) {
-    			line.append(" 准考证号不能为空");
-    		}
-    		if(StringUtils.isBlank(vo.getSubjectCode())) {
-    			line.append(" 科目代码不能为空");
-    		}
-    		if(StringUtils.isBlank(vo.getSubjectName())) {
-    			line.append(" 科目名称不能为空");
-    		}
-    		if(StringUtils.isNotBlank(vo.getExamNumber())) {
-	    		ExamStudent es=studentService.findByExamIdAndExamNumber(examId, vo.getExamNumber());
-	    		if(es==null) {
-	    			line.append(" 考生"+vo.getExamNumber()+"不存在");
-	    		}else {
-	    			vo.setStudent(es);
-	    		}
-    		}
-    		if(line.length()>0) {
-    			err.append(" 第"+(index+2)+"行 "+line);
-    		}
-    	}
-    	if(err.length()>0) {
-    		return err.toString();
-    	}
-    	try {
+		StringBuilder err = new StringBuilder();
+		if (CollectionUtils.isEmpty(list)) {
+			err.append("Excel中没有数据");
+			return err.toString();
+		}
+		int index = 0;
+		for (SubjectSplit vo : list) {
+			index++;
+			StringBuilder line = new StringBuilder();
+			if (StringUtils.isBlank(vo.getExamNumber())) {
+				line.append(" 准考证号不能为空");
+			}
+			if (StringUtils.isBlank(vo.getSubjectCode())) {
+				line.append(" 科目代码不能为空");
+			}
+			if (StringUtils.isBlank(vo.getSubjectName())) {
+				line.append(" 科目名称不能为空");
+			}
+			if (StringUtils.isNotBlank(vo.getExamNumber())) {
+				ExamStudent es = studentService.findByExamIdAndExamNumber(examId, vo.getExamNumber());
+				if (es == null) {
+					line.append(" 考生" + vo.getExamNumber() + "不存在");
+				} else {
+					vo.setStudent(es);
+				}
+			}
+			if (line.length() > 0) {
+				err.append(" 第" + (index + 2) + "行 " + line);
+			}
+		}
+		if (err.length() > 0) {
+			return err.toString();
+		}
+		try {
 			disposeSplit(schoolId, examId, list);
 			disposeSplit(schoolId, examId, list);
 		} catch (StatusException e) {
 		} catch (StatusException e) {
 			err.append(e.getDesc());
 			err.append(e.getDesc());
 			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
 			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
 		} catch (Exception e) {
 		} catch (Exception e) {
-			err.append("导入出错:"+e.getMessage());
+			err.append("导入出错:" + e.getMessage());
 			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
 			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
 		}
 		}
 		return err.toString();
 		return err.toString();
 	}
 	}
-    
-    private void disposeSplit(Integer schoolId, Integer examId, List<SubjectSplit> list) {
-    	int index=0;
-    	Set<String> validSubjects=new HashSet<>();
-    	for(SubjectSplit vo:list) {
-    		index++;
-    		long groupCount=markGroupService.countByExamAndSubject(examId, vo.getStudent().getSubjectCode());
-    		if(groupCount>0) {
-    			throw new StatusException(" 第"+(index+2)+"行 科目"+vo.getStudent().getSubjectCode()+"有分组,请先删除分组再执行");
-    		}
-    		validSubjects.add(vo.getStudent().getSubjectCode());
-    		if(!validSubjects.contains(vo.getSubjectCode())) {
-    			ExamSubject es=subjectDao.findByExamIdAndCode(index, vo.getSubjectCode());
-    			if(es==null) {
-    				es=new ExamSubject();
-    				es.setExamId(examId);
-    				es.setName(vo.getSubjectName());
-    				es.setCode(vo.getSubjectCode());
-    				es.setObjectiveScore(0.0);
-    				es.setSubjectiveScore(0.0);
-    				es.setTotalScore(0.0);
-    				es.setUploadCount(0);
-    				es.setDisplayQuestionName(true);
-    				es.setInspectRound(1);
-    				es.setSelective(false);
-    				subjectDao.save(es);
-    			}else {
-    				long count=markGroupService.countByExamAndSubject(examId, vo.getSubjectCode());
-    	    		if(count>0) {
-    	    			throw new StatusException(" 第"+(index+2)+"行 科目"+vo.getSubjectCode()+"有分组,请先删除分组再执行");
-    	    		}
-    			}
-    			validSubjects.add(vo.getSubjectCode());
-    		}
-    		vo.getStudent().setSubjectCode(vo.getSubjectCode());
-    		vo.getStudent().setSubjectName(vo.getSubjectName());
-    		examStudentDao.save(vo.getStudent());
-    	}
-    	subjectDao.updateUploadCountByExamId(examId);
-    	subjectDao.deleteNoStudentByExamId(examId);
-    }
+
+	private void disposeSplit(Integer schoolId, Integer examId, List<SubjectSplit> list) {
+		int index = 0;
+		Set<String> validSubjects = new HashSet<>();
+		for (SubjectSplit vo : list) {
+			index++;
+			long groupCount = markGroupService.countByExamAndSubject(examId, vo.getStudent().getSubjectCode());
+			if (groupCount > 0) {
+				throw new StatusException(
+						" 第" + (index + 2) + "行 科目" + vo.getStudent().getSubjectCode() + "有分组,请先删除分组再执行");
+			}
+			validSubjects.add(vo.getStudent().getSubjectCode());
+			if (!validSubjects.contains(vo.getSubjectCode())) {
+				ExamSubject es = subjectDao.findByExamIdAndCode(index, vo.getSubjectCode());
+				if (es == null) {
+					es = new ExamSubject();
+					es.setExamId(examId);
+					es.setName(vo.getSubjectName());
+					es.setCode(vo.getSubjectCode());
+					es.setObjectiveScore(0.0);
+					es.setSubjectiveScore(0.0);
+					es.setTotalScore(0.0);
+					es.setUploadCount(0);
+					es.setDisplayQuestionName(true);
+					es.setInspectRound(1);
+					es.setSelective(false);
+					subjectDao.save(es);
+				} else {
+					long count = markGroupService.countByExamAndSubject(examId, vo.getSubjectCode());
+					if (count > 0) {
+						throw new StatusException(" 第" + (index + 2) + "行 科目" + vo.getSubjectCode() + "有分组,请先删除分组再执行");
+					}
+				}
+				validSubjects.add(vo.getSubjectCode());
+			}
+			vo.getStudent().setSubjectCode(vo.getSubjectCode());
+			vo.getStudent().setSubjectName(vo.getSubjectName());
+			examStudentDao.save(vo.getStudent());
+		}
+		subjectDao.updateUploadCountByExamId(examId);
+		subjectDao.deleteNoStudentByExamId(examId);
+	}
+
 }
 }

+ 5 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/MarkGroupServiceImpl.java

@@ -99,6 +99,11 @@ public class MarkGroupServiceImpl extends BaseQueryService<MarkGroup> implements
     public long countByExamAndSubjectAndStatus(Integer examId, String subjectCode, MarkStatus... status) {
     public long countByExamAndSubjectAndStatus(Integer examId, String subjectCode, MarkStatus... status) {
         return groupDao.countByExamIdAndSubjectCodeAndStatus(examId, subjectCode, status);
         return groupDao.countByExamIdAndSubjectCodeAndStatus(examId, subjectCode, status);
     }
     }
+    
+    @Override
+    public long countByExamAndStatus(Integer examId, MarkStatus... status) {
+        return groupDao.countByExamIdAndStatus(examId, status);
+    }
 
 
     @Override
     @Override
     public long countByExamAndSubject(int examId, String subjectCode) {
     public long countByExamAndSubject(int examId, String subjectCode) {

+ 44 - 0
stmms-web/src/main/java/cn/com/qmth/stmms/admin/basic/OverviewController.java

@@ -0,0 +1,44 @@
+package cn.com.qmth.stmms.admin.basic;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import cn.com.qmth.stmms.admin.exam.BaseExamController;
+import cn.com.qmth.stmms.biz.exam.service.CheckStudentService;
+import cn.com.qmth.stmms.biz.exam.service.ExamStudentService;
+import cn.com.qmth.stmms.biz.exam.service.ExamSubjectService;
+import cn.com.qmth.stmms.common.enums.CheckType;
+
+@Controller
+@RequestMapping("/admin/basic/overview")
+public class OverviewController extends BaseExamController {
+	@Autowired
+	private ExamStudentService examStudentService;
+	
+	@Autowired
+	private ExamSubjectService examSubjectService;
+	
+	@Autowired
+	private CheckStudentService checkStudentService;
+
+	@RequestMapping
+	public String roleLise(Model model, HttpServletRequest request) {
+		int examId = getSessionExamId(request);
+		long studentCount=examStudentService.countByExamId(examId);
+		model.addAttribute("studentCount", studentCount);
+		model.addAttribute("subjectCount", examSubjectService.count(examId));
+		if(studentCount>0&&checkStudentService.countByExamIdAndCheckedAndType(examId, false, CheckType.MANUAL)==0) {
+			model.addAttribute("checkStudentOk", true);
+		}else {
+			model.addAttribute("checkStudentOk", false);
+		}
+		model.addAttribute("checkSubjectOk", examSubjectService.checkSubjectForExport(examId));
+		model.addAttribute("checkAbsentOk", examSubjectService.checkSubjectAbsentForExport(examId));
+		return "modules/basic/overview";
+	}
+	
+}

+ 194 - 0
stmms-web/src/main/webapp/WEB-INF/views/modules/basic/overview.jsp

@@ -0,0 +1,194 @@
+<%@ page contentType="text/html;charset=UTF-8" %>
+<%@ include file="/WEB-INF/views/include/taglib.jsp" %>
+<html>
+<head>
+    <title>主页导览</title>
+    <meta name="decorator" content="default"/>
+    <%@include file="/WEB-INF/views/include/head.jsp" %>
+    <%@include file="/WEB-INF/views/include/dialog.jsp" %>
+    <link rel="stylesheet" href="${ctxStatic}/overview/css/overview.css" />
+    <style type="text/css">.sort {
+        color: #0663A2;
+        cursor: pointer;
+    }</style>
+</head>
+<body>
+    <div id="app-guide">
+      <div id="guide-center">
+        <div class="guide-row1">
+          <div class="guide-column1">
+            <div class="guide-card guide-card1">
+              <div class="guide-title">
+                <div class="img-box">
+                  <img src="${ctxStatic}/overview/image/guide1.png" />
+                </div>
+                <div class="txt">系统初始化</div>
+              </div>
+              <div class="guide-body">
+                <a class="my-btn border-c">考试设置</a>
+                <div class="border-c my-btn-box">
+                  <a class="my-btn">考生导入</a>
+                  <div class="custom-box">
+                    <span class="c-label">考生:</span>
+                    <span class="c-value stu-count">${studentCount}</span>
+                    <span class="c-label" style="margin-left: 16px">科目:</span>
+                    <span class="c-value subject-count">${subjectCount}</span>
+                  </div>
+                </div>
+                <a class="my-btn border-c">试卷结构设置</a>
+                <a class="my-btn border-c">用户账号设置</a>
+              </div>
+            </div>
+          </div>
+          <div class="guide-gap x-gap">
+            <img src="${ctxStatic}/overview/image/guide_to_right.png" />
+          </div>
+          <div class="guide-column2">
+            <div class="guide-card guide-card2">
+              <div class="guide-title">
+                <div class="img-box">
+                  <img src="${ctxStatic}/overview/image/guide2.png" />
+                </div>
+                <div class="txt">评卷管理</div>
+              </div>
+              <div class="guide-body2">
+                <div class="step-icon-box">
+                  <span class="circle circle1"></span>
+                  <span class="circle circle2"></span>
+                </div>
+                <div class="step-content-box">
+                  <div class="level1">
+                    <div class="big-title">评卷过程管理</div>
+                    <div class="flex-1 b-left">
+                      <a class="my-btn border-c">评卷进度</a>
+                      <a class="my-btn border-c">分组设置修改</a>
+                      <a class="my-btn border-c">已评任务查看</a>
+                    </div>
+                  </div>
+                  <div class="level2">
+                    <div class="big-title">数据分析</div>
+                    <div class="flex-1">
+                      <a class="my-btn border-c">科目分析</a>
+                    </div>
+                  </div>
+                </div>
+              </div>
+            </div>
+          </div>
+          <div class="guide-gap x-gap">
+            <img src="${ctxStatic}/overview/image/guide_to_right.png" />
+          </div>
+          <div class="guide-column3">
+            <div class="guide-card guide-card3">
+              <div class="guide-title">
+                <div class="img-box">
+                  <img src="${ctxStatic}/overview/image/guide3.png" />
+                </div>
+                <div class="txt">异常卷处理</div>
+              </div>
+              <div class="guide-body">
+                <a class="my-btn border-c">打回卷处理</a>
+                <a class="my-btn border-c">问题卷处理</a>
+                <a class="my-btn border-c">仲裁卷处理</a>
+              </div>
+            </div>
+          </div>
+        </div>
+        <div class="guide-row2">
+          <div class="guide-column1"></div>
+          <div class="guide-gap x-gap" style="opacity: 0">
+            <img src="${ctxStatic}/overview/image/guide_to_right.png" />
+          </div>
+          <div class="guide-column2"></div>
+          <div class="guide-gap x-gap" style="opacity: 0">
+            <img src="${ctxStatic}/overview/image/guide_to_right.png" />
+          </div>
+          <div class="guide-column3">
+            <div class="guide-gap y-gap">
+              <img src="${ctxStatic}/overview/image/guide_to_bottom.png" />
+            </div>
+          </div>
+        </div>
+        <div class="guide-row3">
+          <div class="guide-column1">
+            <div class="guide-card guide-card4">
+              <div class="guide-title">
+                <div class="img-box">
+                  <img src="${ctxStatic}/overview/image/guide6.png" />
+                </div>
+                <div class="txt">成绩复查</div>
+              </div>
+              <div class="guide-body">
+                <a class="my-btn border-c">关闭考试</a>
+                <a class="my-btn border-c">导入待复查考生</a>
+                <a class="my-btn border-c">进入复核</a>
+              </div>
+            </div>
+          </div>
+          <div class="guide-gap x-gap">
+            <img src="${ctxStatic}/overview/image/guide_to_left.png" />
+          </div>
+          <div class="guide-column2">
+            <div class="guide-card guide-card5">
+              <div class="guide-title">
+                <div class="img-box">
+                  <img src="${ctxStatic}/overview/image/guide5.png" />
+                </div>
+                <div class="txt">成绩导出</div>
+              </div>
+              <div class="guide-body5">
+                <div class="level1">
+                  <div class="step-index-box">
+                    <span class="index1">1</span>
+                    <span class="index2">2</span>
+                    <span class="index3">3</span>
+                  </div>
+                  <div class="flex-1">
+                    <a class="my-btn border-c"
+                      >数据检查 - 人工确认
+                      <c:if test="${checkStudentOk==true}">
+                      <img src="${ctxStatic}/overview/image/done.png" />
+                      </c:if>
+                    </a>
+                    <a class="my-btn border-c"
+                      >检查科目进度100%且关闭
+                      <c:if test="${checkSubjectOk==true}">
+                      <img src="${ctxStatic}/overview/image/done.png" />
+                      </c:if>
+                    </a>
+                    <a class="my-btn border-c"
+                      >缺考考生导入
+                      <c:if test="${checkAbsentOk==true}">
+                      <img src="${ctxStatic}/overview/image/done.png" />
+                      </c:if>
+                    </a>
+                  </div>
+                </div>
+                <div class="level2">
+                  <a class="my-btn border-c">成绩导出</a>
+                </div>
+              </div>
+            </div>
+          </div>
+          <div class="guide-gap x-gap">
+            <img src="${ctxStatic}/overview/image/guide_to_left.png" />
+          </div>
+          <div class="guide-column3">
+            <div class="guide-card guide-card6">
+              <div class="guide-title">
+                <div class="img-box">
+                  <img src="${ctxStatic}/overview/image/guide4.png" />
+                </div>
+                <div class="txt">复核处理</div>
+              </div>
+              <div class="guide-body">
+                <a class="my-btn border-c">任务复核</a>
+                <a class="my-btn border-c">全卷复核</a>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </body>
+</html>

+ 293 - 0
stmms-web/src/main/webapp/static/overview/css/overview.css

@@ -0,0 +1,293 @@
+#app-guide {
+  height: 100%;
+  background: url(imgs/guide_bg.png) 0 0 no-repeat;
+  background-size: 100% 100%;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+#app-guide * {
+  box-sizing: border-box;
+}
+#app-guide #guide-center .guide-card1,
+#app-guide #guide-center .guide-card2,
+#app-guide #guide-center .guide-card3 {
+  height: 298px;
+}
+#app-guide #guide-center .guide-card4,
+#app-guide #guide-center .guide-card5,
+#app-guide #guide-center .guide-card6 {
+  height: 262px;
+}
+#app-guide #guide-center .guide-gap {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+#app-guide #guide-center .guide-gap.x-gap {
+  padding: 0 0.8vw;
+}
+#app-guide #guide-center .guide-gap.x-gap img {
+  height: 22px;
+}
+#app-guide #guide-center .guide-gap.y-gap {
+  padding: 0.8vw 0;
+}
+#app-guide #guide-center .guide-gap.y-gap img {
+  width: 22px;
+}
+#app-guide #guide-center .guide-row1,
+#app-guide #guide-center .guide-row2,
+#app-guide #guide-center .guide-row3 {
+  display: flex;
+}
+#app-guide #guide-center .guide-column1 {
+  width: 234px;
+}
+#app-guide #guide-center .guide-column2 {
+  width: 350px;
+}
+#app-guide #guide-center .guide-column3 {
+  width: 222px;
+}
+#app-guide .guide-card {
+  background-color: #fff;
+  border: 1px solid #ddd;
+  border-radius: 10px;
+  padding: 16px;
+}
+#app-guide .guide-card .guide-title {
+  height: 32px;
+  display: flex;
+  align-items: center;
+}
+#app-guide .guide-card .guide-title .img-box {
+  width: 32px;
+  height: 32px;
+  border-radius: 16px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  border: 1px solid #ddd;
+}
+#app-guide .guide-card .guide-title .img-box img {
+  height: 16px;
+}
+#app-guide .guide-card .guide-title .txt {
+  font-weight: 500;
+  color: #000201;
+  margin-left: 6px;
+  font-size: 16px;
+}
+#app-guide .guide-card .guide-body {
+  padding: 10px 0;
+}
+#app-guide .guide-card .guide-body5 {
+  padding: 10px 0;
+}
+#app-guide .guide-card .guide-body5 .level2 {
+  margin-top: 8px;
+}
+#app-guide .guide-card .guide-body5 .level1 {
+  display: flex;
+}
+#app-guide .guide-card .guide-body5 .level1 .my-btn img {
+  position: absolute;
+  right: 28px;
+  height: 16px;
+  z-index: 2;
+  top: 11px;
+}
+#app-guide .guide-card .guide-body5 .level1 .flex-1 {
+  flex: 1;
+  padding-left: 15px;
+}
+#app-guide .guide-card .guide-body5 .step-index-box {
+  position: relative;
+  width: 1px;
+  margin-left: 16px;
+}
+#app-guide .guide-card .guide-body5 .step-index-box span {
+  border: 1px solid #7cb5ec;
+  color: #0088cc;
+  font-weight: bold;
+  position: absolute;
+  width: 18px;
+  height: 18px;
+  border-radius: 50%;
+  z-index: 1;
+  background-color: #fff;
+  right: -8px;
+  line-height: 16px;
+  text-align: center;
+}
+#app-guide .guide-card .guide-body5 .step-index-box span.index1 {
+  top: 10px;
+}
+#app-guide .guide-card .guide-body5 .step-index-box span.index2 {
+  top: 55px;
+}
+#app-guide .guide-card .guide-body5 .step-index-box span.index3 {
+  bottom: 12px;
+}
+#app-guide .guide-card .guide-body5 .step-index-box:after {
+  content: "";
+  position: absolute;
+  top: 20px;
+  right: 0;
+  bottom: 24px;
+  width: 1px;
+  background: #ddd;
+}
+#app-guide .guide-card .guide-body2 {
+  display: flex;
+}
+#app-guide .guide-card .guide-body2 .step-icon-box {
+  position: relative;
+  width: 1px;
+  margin-left: 16px;
+}
+#app-guide .guide-card .guide-body2 .step-icon-box:after {
+  content: "";
+  position: absolute;
+  top: 0;
+  right: 0;
+  bottom: 24px;
+  width: 1px;
+  background: #ddd;
+}
+#app-guide .guide-card .guide-body2 .step-icon-box .circle {
+  position: absolute;
+  width: 10px;
+  height: 10px;
+  border-radius: 5px;
+  border: 2px solid #0088cc;
+  left: -5px;
+  z-index: 1;
+  background-color: #fff;
+}
+#app-guide .guide-card .guide-body2 .step-icon-box .circle.circle1 {
+  top: 61px;
+}
+#app-guide .guide-card .guide-body2 .step-icon-box .circle.circle2 {
+  bottom: 14px;
+}
+#app-guide .guide-card .guide-body2 .step-content-box {
+  flex: 1;
+  padding-left: 8px;
+}
+#app-guide .guide-card .guide-body2 .step-content-box .level1 {
+  display: flex;
+  align-items: center;
+  margin-bottom: 16px;
+}
+#app-guide .guide-card .guide-body2 .step-content-box .level2 {
+  display: flex;
+  align-items: center;
+}
+#app-guide .guide-card .guide-body2 .step-content-box .level2 .flex-1 {
+  position: relative;
+}
+#app-guide .guide-card .guide-body2 .step-content-box .level2 .flex-1:after {
+  content: "";
+  position: absolute;
+  height: 1px;
+  width: 42px;
+  top: 19px;
+  left: -42px;
+  background-color: #ddd;
+}
+#app-guide .guide-card .guide-body2 .step-content-box .flex-1 {
+  flex: 1;
+}
+#app-guide .guide-card .guide-body2 .step-content-box .b-left {
+  position: relative;
+}
+#app-guide .guide-card .guide-body2 .step-content-box .b-left:after {
+  content: "";
+  width: 1px;
+  left: -8px;
+  top: 19px;
+  background-color: #ddd;
+  bottom: 18px;
+  position: absolute;
+}
+#app-guide .guide-card .guide-body2 .step-content-box .b-left .my-btn:nth-child(1):after {
+  content: "";
+  position: absolute;
+  width: 8px;
+  height: 1px;
+  top: 18px;
+  left: -8px;
+  background-color: #ddd;
+}
+#app-guide .guide-card .guide-body2 .step-content-box .b-left .my-btn:nth-child(2):after {
+  content: "";
+  position: absolute;
+  width: 16px;
+  height: 1px;
+  top: 18px;
+  left: -16px;
+  background-color: #ddd;
+}
+#app-guide .guide-card .guide-body2 .step-content-box .b-left .my-btn:nth-child(3):after {
+  content: "";
+  position: absolute;
+  width: 8px;
+  height: 1px;
+  top: 18px;
+  left: -8px;
+  background-color: #ddd;
+}
+#app-guide .guide-card .guide-body2 .step-content-box .big-title {
+  width: 105px;
+}
+#app-guide .border-c {
+  border: 1px solid #ccc;
+  border-radius: 8px;
+}
+#app-guide .my-btn {
+  font-size: 14px;
+  position: relative;
+  display: block;
+  padding: 8px 30px 8px 12px;
+  color: #333;
+  background-size: 16px 16px;
+  text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);
+  border-bottom-color: #b3b3b3;
+  background: url(imgs/btn_link.png) no-repeat calc(100% - 8px) center / 16px 16px, linear-gradient(180deg, #ffffff 0%, #e7e7e6 100%);
+  text-decoration: none;
+  cursor: pointer;
+  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+}
+#app-guide .my-btn:hover {
+  background: url(imgs/btn_link.png) no-repeat calc(100% - 8px) center / 16px 16px, linear-gradient(180deg, #e7e7e6 0%, #e7e7e6 100%);
+  box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
+}
+#app-guide .my-btn:active {
+  background: url(imgs/btn_link.png) no-repeat calc(100% - 8px) center / 16px 16px, linear-gradient(180deg, #ccc 0%, #e7e7e6 100%);
+}
+#app-guide .my-btn:not(:last-child) {
+  margin-bottom: 8px;
+}
+#app-guide .my-btn-box {
+  overflow: hidden;
+}
+#app-guide .my-btn-box:not(:last-child) {
+  margin-bottom: 8px;
+}
+#app-guide .my-btn-box .my-btn {
+  border-bottom-left-radius: 0 !important;
+  border-bottom-right-radius: 0 !important;
+}
+#app-guide .my-btn-box .custom-box {
+  padding: 4px 12px;
+  background-color: #fff;
+  font-size: 14px;
+}
+#app-guide .my-btn-box .custom-box .c-label {
+  color: #595959;
+}
+#app-guide .my-btn-box .custom-box .c-value {
+  color: #ff8463;
+}

BIN
stmms-web/src/main/webapp/static/overview/image/btn_link.png


BIN
stmms-web/src/main/webapp/static/overview/image/done.png


BIN
stmms-web/src/main/webapp/static/overview/image/guide1.png


BIN
stmms-web/src/main/webapp/static/overview/image/guide2.png


BIN
stmms-web/src/main/webapp/static/overview/image/guide3.png


BIN
stmms-web/src/main/webapp/static/overview/image/guide4.png


BIN
stmms-web/src/main/webapp/static/overview/image/guide5.png


BIN
stmms-web/src/main/webapp/static/overview/image/guide6.png


BIN
stmms-web/src/main/webapp/static/overview/image/guide_bg.png


BIN
stmms-web/src/main/webapp/static/overview/image/guide_to_bottom.png


BIN
stmms-web/src/main/webapp/static/overview/image/guide_to_left.png


BIN
stmms-web/src/main/webapp/static/overview/image/guide_to_right.png