yin hace 1 mes
padre
commit
430a511a14
Se han modificado 25 ficheros con 418 adiciones y 40 borrados
  1. 0 0
      install/mysql/upgrade/1.6.0.sql
  2. 3 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/ExamQuestionDao.java
  3. 2 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/SubjectUserDao.java
  4. 2 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/ExamQuestionService.java
  5. 1 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/SubjectUserService.java
  6. 6 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/ExamQuestionServiceImpl.java
  7. 3 3
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/ExamStudentServiceImpl.java
  8. 5 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/SubjectUserServiceImpl.java
  9. 2 2
      stmms-common/src/main/java/cn/com/qmth/stmms/common/utils/VersionInfo.java
  10. 152 0
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/dto/ProblemHistoryDTO.java
  11. 5 0
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/InspectedController.java
  12. 2 1
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/PaperController.java
  13. 64 11
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/ProblemHistoryController.java
  14. 12 0
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/ScanController.java
  15. 1 1
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/thread/DataSyncThread.java
  16. 1 1
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/thread/OnlineExamThread.java
  17. 110 4
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/user/UserController.java
  18. 10 0
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/vo/ScanInfoVO.java
  19. 1 1
      stmms-web/src/main/java/cn/com/qmth/stmms/api/controller/CoreController.java
  20. 2 6
      stmms-web/src/main/java/cn/com/qmth/stmms/api/controller/ExamStudentController.java
  21. 5 3
      stmms-web/src/main/webapp/WEB-INF/views/modules/exam/groupAdd.jsp
  22. 7 5
      stmms-web/src/main/webapp/WEB-INF/views/modules/exam/groupEditFull.jsp
  23. 8 0
      stmms-web/src/main/webapp/WEB-INF/views/modules/exam/problemHistory.jsp
  24. 3 1
      stmms-web/src/main/webapp/WEB-INF/views/modules/exam/scanInfo.jsp
  25. 11 1
      stmms-web/src/main/webapp/WEB-INF/views/modules/user/userList.jsp

+ 0 - 0
install/mysql/upgrade/1.5.2.sql → install/mysql/upgrade/1.6.0.sql


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

@@ -115,4 +115,7 @@ public interface ExamQuestionDao extends JpaRepository<ExamQuestion, Integer>, J
     @Query("update ExamQuestion q set q.name=?2 where q.id=?1 ")
     public void updateMainName(Integer id, String name);
 
+    @Modifying
+    @Query("update ExamQuestion q set q.trackCount=?2 where q.id=?1 ")
+    void updateTrackCount(Integer id, int trackCount);
 }

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

@@ -18,4 +18,6 @@ public interface SubjectUserDao extends PagingAndSortingRepository<SubjectUser,
     @Modifying
     @Query("delete from SubjectUser su where su.userId=?1")
     void deleteByUserId(Integer userId);
+
+    List<SubjectUser> findBySubjectCode(String subjectCode);
 }

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

@@ -80,4 +80,6 @@ public interface ExamQuestionService {
     double sumTotalScoreByGroupNumber(int examId, String subjectCode, boolean objective, Integer groupNumber);
 
 	void updateMainName(Integer id,String name);
+
+    void updateTrackCount(Integer id, int trackCount);
 }

+ 1 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/SubjectUserService.java

@@ -23,4 +23,5 @@ public interface SubjectUserService {
 
     void updateByUserId(Integer userId, Set<String> subjectCodeSet);
 
+    List<SubjectUser> findBySubjectCode(String subjectCode);
 }

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

@@ -365,4 +365,10 @@ public class ExamQuestionServiceImpl extends BaseQueryService<ExamQuestion> impl
     	questionDao.updateMainName(id, name);
 	}
 
+    @Override
+    @Transactional
+    public void updateTrackCount(Integer id, int trackCount) {
+        questionDao.updateTrackCount(id, trackCount);
+    }
+
 }

+ 3 - 3
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/ExamStudentServiceImpl.java

@@ -125,7 +125,7 @@ public class ExamStudentServiceImpl extends BaseQueryService<ExamStudent> implem
                 subject.setLevel(StringUtils.trimToNull(student.getSubjectLevel()));
                 subject.setCategory(StringUtils.trimToNull(student.getSubjectCategory()));
                 subject.setRemark(StringUtils.trimToNull(student.getSubjectRemark()));
-                subject.setDisplayQuestionName(false);
+                subject.setDisplayQuestionName(true);
                 subject.setInspectRound(1);
             } else {
                 subject = subjectMap.get(student.getSubjectCode());
@@ -154,7 +154,7 @@ public class ExamStudentServiceImpl extends BaseQueryService<ExamStudent> implem
                 subject.setTotalScore(0d);
                 subject.setUploadCount(0);
                 subject.setRemark(es.getRemark());
-                subject.setDisplayQuestionName(false);
+                subject.setDisplayQuestionName(true);
                 subject.setInspectRound(1);
                 subject.setSelective(false);
             } else {
@@ -213,7 +213,7 @@ public class ExamStudentServiceImpl extends BaseQueryService<ExamStudent> implem
             subject.setTotalScore(0d);
             subject.setUploadCount(0);
             subject.setRemark(StringUtils.trimToNull(student.getSubjectRemark()));
-            subject.setDisplayQuestionName(false);
+            subject.setDisplayQuestionName(true);
             subject.setInspectRound(1);
             subject.setSelective(false);
             subjectService.save(subject);

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

@@ -87,4 +87,9 @@ public class SubjectUserServiceImpl extends BaseQueryService<SubjectUser> implem
         }
     }
 
+    @Override
+    public List<SubjectUser> findBySubjectCode(String subjectCode) {
+        return subjectUserDao.findBySubjectCode(subjectCode);
+    }
+
 }

+ 2 - 2
stmms-common/src/main/java/cn/com/qmth/stmms/common/utils/VersionInfo.java

@@ -5,7 +5,7 @@ package cn.com.qmth.stmms.common.utils;
  */
 public class VersionInfo {
 
-    public static final String NAME = "1.5.2";
+    public static final String NAME = "1.6.0";
 
-    public static final String DATE = "20241220";
+    public static final String DATE = "20250520";
 }

+ 152 - 0
stmms-web/src/main/java/cn/com/qmth/stmms/admin/dto/ProblemHistoryDTO.java

@@ -0,0 +1,152 @@
+package cn.com.qmth.stmms.admin.dto;
+
+import cn.com.qmth.stmms.common.annotation.ExcelField;
+
+public class ProblemHistoryDTO {
+
+    @ExcelField(title = "课程代码", align = 2, sort = 20)
+    private String subjectCode;
+
+    @ExcelField(title = "课程名称", align = 2, sort = 30)
+    private String subjectName;
+
+    @ExcelField(title = "分组序号", align = 2, sort = 40)
+    private Integer groupNumber;
+
+    @ExcelField(title = "状态", align = 2, sort = 50)
+    private String status;
+
+    @ExcelField(title = "准考证号", align = 2, sort = 60)
+    private String examNumber;
+
+    @ExcelField(title = "学号", align = 2, sort = 70)
+    private String studentCode;
+
+    @ExcelField(title = "密号", align = 2, sort = 80)
+    private String secretNumber;
+
+    @ExcelField(title = "姓名", align = 2, sort = 90)
+    private String name;
+
+    @ExcelField(title = "评卷员", align = 2, sort = 100)
+    private String markLogin;
+
+    @ExcelField(title = "提交时间", align = 2, sort = 110)
+    private String markTime;
+
+    @ExcelField(title = "问题类型", align = 2, sort = 130)
+    private String problemType;
+
+    @ExcelField(title = "处理人", align = 2, sort = 140)
+    private String problemUserName;
+
+    @ExcelField(title = "处理时间", align = 2, sort = 150)
+    private String problemRestTime;
+
+    public ProblemHistoryDTO() {
+    }
+
+    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 Integer getGroupNumber() {
+        return groupNumber;
+    }
+
+    public void setGroupNumber(Integer groupNumber) {
+        this.groupNumber = groupNumber;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public String getExamNumber() {
+        return examNumber;
+    }
+
+    public void setExamNumber(String examNumber) {
+        this.examNumber = examNumber;
+    }
+
+    public String getStudentCode() {
+        return studentCode;
+    }
+
+    public void setStudentCode(String studentCode) {
+        this.studentCode = studentCode;
+    }
+
+    public String getSecretNumber() {
+        return secretNumber;
+    }
+
+    public void setSecretNumber(String secretNumber) {
+        this.secretNumber = secretNumber;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getMarkLogin() {
+        return markLogin;
+    }
+
+    public void setMarkLogin(String markLogin) {
+        this.markLogin = markLogin;
+    }
+
+    public String getMarkTime() {
+        return markTime;
+    }
+
+    public void setMarkTime(String markTime) {
+        this.markTime = markTime;
+    }
+
+    public String getProblemType() {
+        return problemType;
+    }
+
+    public void setProblemType(String problemType) {
+        this.problemType = problemType;
+    }
+
+    public String getProblemUserName() {
+        return problemUserName;
+    }
+
+    public void setProblemUserName(String problemUserName) {
+        this.problemUserName = problemUserName;
+    }
+
+    public String getProblemRestTime() {
+        return problemRestTime;
+    }
+
+    public void setProblemRestTime(String problemRestTime) {
+        this.problemRestTime = problemRestTime;
+    }
+}

+ 5 - 0
stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/InspectedController.java

@@ -334,6 +334,7 @@ public class InspectedController extends BaseExamController {
                 lockService.watch(LockType.EXAM_SUBJECT, student.getExamId(), student.getSubjectCode());
                 lockService.waitlock(LockType.STUDENT, studentId);
                 if (inspectedService.cancelByStudent(studentId)) {
+                    RequestUtils.setLog(request, "准考证号:"+student.getExamNumber()+" 试卷取消复核");
                     obj.accumulate("success", true);
                 } else {
                     obj.accumulate("success", false);
@@ -622,6 +623,7 @@ public class InspectedController extends BaseExamController {
     public String batchCancel(HttpServletRequest request, @RequestParam Integer[] ids) {
         WebUser wu = RequestUtils.getWebUser(request);
         // String subjectCode = "";
+        StringBuilder sb=new StringBuilder();
         for (Integer id : ids) {
             ExamStudent student = studentService.findById(id);
             // subjectCode = student.getSubjectCode();
@@ -630,6 +632,7 @@ public class InspectedController extends BaseExamController {
                     lockService.watch(LockType.EXAM_SUBJECT, student.getExamId(), student.getSubjectCode());
                     lockService.waitlock(LockType.STUDENT, student.getId());
                     inspectedService.cancelByStudent(id);
+                    sb.append(" 准考证号:"+student.getExamNumber());
                 } catch (Exception e) {
                     log.error("back inspected error", e);
                 } finally {
@@ -638,6 +641,8 @@ public class InspectedController extends BaseExamController {
                 }
             }
         }
+        sb.append(" 试卷取消复核");
+        RequestUtils.setLog(request, sb.toString());
         return "redirect:/admin/exam/inspected/list";
     }
 

+ 2 - 1
stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/PaperController.java

@@ -553,8 +553,9 @@ public class PaperController extends BaseExamController {
         String t = query.getTotalScoreNotEqual() == null ? "" : query.getTotalScoreNotEqual().toString();
         ExamQuestion newQ = questionService.findByExamAndSubjectAndObjectiveAndMainNumberAndSubNumber(examId,
                 question.getSubjectCode(), question.isObjective(), question.getMainNumber(), question.getSubNumber());
-        if (!old.isObjective() && !enableUpdate) {// 只能修改大题昵称的主观题
+        if (!old.isObjective() && !enableUpdate) {// 只能修改大题昵称的主观题、可修改给分次数
             questionService.updateMainName(id, question.getName());
+            questionService.updateTrackCount(id,question.getTrackCount()==null?0:question.getTrackCount());
             return "redirect:/admin/exam/paper/detail?subjectCode=" + question.getSubjectCode() + "&pageNumber="
                     + query.getPageNumber() + "&code=" + query.getCode() + "&category=" + query.getCategory()
                     + "&level=" + query.getLevel() + "&upload=" + u + "&totalScoreNotEqual=" + t;

+ 64 - 11
stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/ProblemHistoryController.java

@@ -6,7 +6,9 @@ import java.util.List;
 import java.util.Map;
 
 import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 
+import cn.com.qmth.stmms.admin.dto.ProblemHistoryDTO;
 import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -14,14 +16,11 @@ 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 org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.servlet.mvc.support.RedirectAttributes;
 
-import cn.com.qmth.stmms.biz.exam.model.Exam;
-import cn.com.qmth.stmms.biz.exam.model.ExamQuestion;
-import cn.com.qmth.stmms.biz.exam.model.ExamStudent;
-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.*;
 import cn.com.qmth.stmms.biz.exam.service.ExamQuestionService;
 import cn.com.qmth.stmms.biz.exam.service.ExamService;
 import cn.com.qmth.stmms.biz.exam.service.ExamStudentService;
@@ -40,13 +39,9 @@ import cn.com.qmth.stmms.biz.user.service.UserService;
 import cn.com.qmth.stmms.common.annotation.Logging;
 import cn.com.qmth.stmms.common.annotation.RoleRequire;
 import cn.com.qmth.stmms.common.domain.WebUser;
-import cn.com.qmth.stmms.common.enums.HistoryStatus;
-import cn.com.qmth.stmms.common.enums.LibraryStatus;
-import cn.com.qmth.stmms.common.enums.LockType;
-import cn.com.qmth.stmms.common.enums.LogType;
-import cn.com.qmth.stmms.common.enums.MarkStatus;
-import cn.com.qmth.stmms.common.enums.Role;
+import cn.com.qmth.stmms.common.enums.*;
 import cn.com.qmth.stmms.common.utils.DateUtils;
+import cn.com.qmth.stmms.common.utils.ExportExcel;
 import cn.com.qmth.stmms.common.utils.RequestUtils;
 
 @Controller
@@ -185,4 +180,62 @@ public class ProblemHistoryController extends BaseExamController {
         }
         return "redirect:/admin/exam/problem/history";
     }
+
+    @Logging(menu = "导出问题卷", type = LogType.EXPORT)
+    @RequestMapping(value = "/export", method = RequestMethod.POST)
+    public String exportFile(ProblemHistorySearchQuery query, HttpServletRequest request, HttpServletResponse response,
+                             RedirectAttributes redirectAttributes) {
+        try {
+            String fileName = "问题卷数据.xlsx";
+            WebUser wu = RequestUtils.getWebUser(request);
+            int examId = getSessionExamId(request);
+            List<ProblemType> problemTypes = problemService.findByExamId(examId);
+            Map<Integer, ProblemType> problemMap = new HashMap<Integer, ProblemType>();
+            for (ProblemType problemType : problemTypes) {
+                problemMap.put(problemType.getId(), problemType);
+            }
+            if (wu.isSubjectHeader() && StringUtils.isBlank(query.getSubjectCode())) {
+                String subjectCodeIn = StringUtils.join(wu.getSubjectCodeSet(), ",");
+                query.setSubjectCodeIn(subjectCodeIn);
+            }
+            if (query.getStatus() == null) {
+                query.setStatus(HistoryStatus.WAITING);
+            }
+            query.setExamId(examId);
+            query.setPageNumber(1);
+            query.setPageSize(Integer.MAX_VALUE);
+            query.orderByExamNumber();
+            query = historyService.findByQuery(query);
+            List<ProblemHistoryDTO> list = new LinkedList<ProblemHistoryDTO>();
+            for (ProblemHistory history : query.getResult()) {
+                ExamStudent student = studentService.findById(history.getStudentId());
+                ProblemHistoryDTO dto = new ProblemHistoryDTO();
+                dto.setSubjectCode(student.getSubjectCode());
+                dto.setSubjectName(student.getSubjectName());
+                dto.setStatus(query.getStatus().getName());
+                dto.setGroupNumber(history.getGroupNumber());
+                dto.setExamNumber(student.getExamNumber());
+                dto.setStudentCode(student.getStudentCode());
+                dto.setSecretNumber(student.getSecretNumber());
+                dto.setName(student.getName());
+                dto.setProblemType(problemMap.get(history.getProblemId()).getName());
+                if (history.getMarkerId() != null) {
+                    User user = userService.findByMarkerId(history.getMarkerId());
+                    dto.setMarkLogin(user.getLoginName() + " " + user.getName());
+                    dto.setMarkTime(DateUtils.formatDateTime(history.getCreateTime()));
+                }
+                if (history.getUserId() != null) {
+                    User user = userService.findById(history.getUserId());
+                    dto.setProblemUserName(user.getLoginName() + " " + user.getName());
+                    dto.setProblemRestTime(DateUtils.formatDateTime(history.getUpdateTime()));
+                }
+                list.add(dto);
+            }
+            new ExportExcel("问题卷数据", ProblemHistoryDTO.class).setDataList(list).write(response, fileName).dispose();
+            return null;
+        } catch (Exception e) {
+            addMessage(redirectAttributes, "导出问题卷数据失败!" + e.getMessage());
+        }
+        return "redirect:/admin/exam/problem/history";
+    }
 }

+ 12 - 0
stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/ScanController.java

@@ -82,6 +82,12 @@ public class ScanController extends BaseExamController {
             long sheetCount2 = new BigDecimal(sheetCount).divide(new BigDecimal(2), 0, BigDecimal.ROUND_HALF_UP)
                     .longValue();
             vo.setScanSheetCount(sheetCount2);
+            ExamStudentSearchQuery studentSearchQuery = new ExamStudentSearchQuery();
+            studentSearchQuery.setExamId(examId);
+            studentSearchQuery.setSubjectCode(subject.getCode());
+            studentSearchQuery.setManualAbsent(true);
+            long manualAbsentCount = studentService.countByQuery(studentSearchQuery);
+            vo.setManualAbsentCount(manualAbsentCount);
             list.add(vo);
         }
 
@@ -208,6 +214,12 @@ public class ScanController extends BaseExamController {
                     vo.setTotalCount(studentService.countByExamIdAndExamSite(examId, examSite));
                     vo.setScanCount(studentService.countByExamIdAndExamSite(examId, examSite, true));
                     vo.setScanSheetCount(studentService.countSheetCountByExamIdAndExamSite(examId, examSite) / 2);
+                    ExamStudentSearchQuery studentSearchQuery = new ExamStudentSearchQuery();
+                    studentSearchQuery.setExamId(examId);
+                    studentSearchQuery.setExamSite(examSite);
+                    studentSearchQuery.setManualAbsent(true);
+                    long manualAbsentCount = studentService.countByQuery(studentSearchQuery);
+                    vo.setManualAbsentCount(manualAbsentCount);
                     list.add(vo);
                 }
                 query.setTotalCount(result.size());

+ 1 - 1
stmms-web/src/main/java/cn/com/qmth/stmms/admin/thread/DataSyncThread.java

@@ -239,7 +239,7 @@ public class DataSyncThread implements Runnable {
         subject.setSubjectiveScore(0d);
         subject.setTotalScore(0d);
         subject.setUploadCount(0);
-        subject.setDisplayQuestionName(false);
+        subject.setDisplayQuestionName(true);
         subject.setInspectRound(1);
         subject.setSelective(false);
         subjectService.save(subject);

+ 1 - 1
stmms-web/src/main/java/cn/com/qmth/stmms/admin/thread/OnlineExamThread.java

@@ -221,7 +221,7 @@ public class OnlineExamThread implements Runnable {
         subject.setSubjectiveScore(0d);
         subject.setTotalScore(0d);
         subject.setUploadCount(0);
-        subject.setDisplayQuestionName(false);
+        subject.setDisplayQuestionName(true);
         subject.setInspectRound(1);
         subject.setSelective(false);
         subjectService.save(subject);

+ 110 - 4
stmms-web/src/main/java/cn/com/qmth/stmms/admin/user/UserController.java

@@ -1,10 +1,12 @@
 package cn.com.qmth.stmms.admin.user;
 
+import java.io.ByteArrayInputStream;
 import java.util.*;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.apache.commons.io.output.ByteArrayOutputStream;
 import org.apache.commons.lang.StringEscapeUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -19,6 +21,8 @@ import org.springframework.web.multipart.MultipartFile;
 import org.springframework.web.servlet.ModelAndView;
 import org.springframework.web.servlet.mvc.support.RedirectAttributes;
 
+import com.qmth.boot.tools.io.ZipWriter;
+
 import cn.com.qmth.stmms.admin.dto.MarkerDTO;
 import cn.com.qmth.stmms.admin.dto.SubjectUserDTO;
 import cn.com.qmth.stmms.admin.exam.BaseExamController;
@@ -37,14 +41,12 @@ import cn.com.qmth.stmms.biz.user.service.UserService;
 import cn.com.qmth.stmms.biz.user.service.query.UserSearchQuery;
 import cn.com.qmth.stmms.common.annotation.Logging;
 import cn.com.qmth.stmms.common.annotation.RoleRequire;
+import cn.com.qmth.stmms.common.domain.WebUser;
 import cn.com.qmth.stmms.common.enums.LogType;
 import cn.com.qmth.stmms.common.enums.Role;
 import cn.com.qmth.stmms.common.enums.SystemAuthType;
 import cn.com.qmth.stmms.common.enums.UserSource;
-import cn.com.qmth.stmms.common.utils.EncryptUtils;
-import cn.com.qmth.stmms.common.utils.ExportExcel;
-import cn.com.qmth.stmms.common.utils.ImportExcel;
-import cn.com.qmth.stmms.common.utils.RequestUtils;
+import cn.com.qmth.stmms.common.utils.*;
 import net.sf.json.JSONObject;
 
 @Controller
@@ -477,6 +479,110 @@ public class UserController extends BaseExamController {
         return "redirect:/admin/user/list";
     }
 
+    @Logging(menu = "导出用户", type = LogType.EXPORT)
+    @RequestMapping(value = "/exportSubject", method = RequestMethod.POST)
+    public String exportSubject(UserSearchQuery query, HttpServletRequest request, HttpServletResponse response,
+            RedirectAttributes redirectAttributes) {
+        int examId = getSessionExamId(request);
+        WebUser wu = RequestUtils.getWebUser(request);
+        try {
+            String fileName = "用户数据.zip";
+            response.reset();
+            response.setContentType("application/octet-stream; charset=utf-8");
+            ZipWriter writer = ZipWriter.create(response.getOutputStream());
+            response.setHeader("Content-Disposition", "attachment; filename=" + Encodes.urlEncode(fileName));
+            List<ExamSubject> subjectList = getExamSubject(examId, wu);
+            Map<String, MarkGroup> groupMap = new HashMap<String, MarkGroup>();
+            Map<String, String> collegeMap = new HashMap<String, String>();
+            for (ExamSubject subject : subjectList) {
+                String subjectName = subject.getCode() + "-" + subject.getName();
+                if (query.getRole() != null && query.getRole().equals(Role.MARKER)) {
+                    MarkerSearchQuery mQuery = new MarkerSearchQuery();
+                    mQuery.setExamId(examId);
+                    mQuery.setSubjectCode(subject.getCode());
+                    mQuery.setLoginName(query.getLoginName());
+                    mQuery.setName(query.getName());
+                    mQuery.setPageSize(Integer.MAX_VALUE);
+                    mQuery = markerService.findByQuery(mQuery);
+                    List<MarkerDTO> list = new ArrayList<MarkerDTO>();
+                    for (Marker m : mQuery.getResult()) {
+                        MarkerDTO s = new MarkerDTO();
+                        if (collegeMap.get(subject.getCode()) == null) {
+                            List<String> colleges = studentService.findDistinctCollegeBySubjectCode(examId,
+                                    m.getSubjectCode());
+                            collegeMap.put(subject.getCode(), StringUtils.join(colleges, SPLIT));
+                        }
+                        s.setSubjectCode(subject.getCode());
+                        s.setSubjectName(subject.getName());
+                        String groupKey = m.getSubjectCode() + "/t" + m.getGroupNumber();
+                        MarkGroup group = groupMap.get(groupKey);
+                        if (group == null) {
+                            group = groupService.findOne(examId, m.getSubjectCode(), m.getGroupNumber());
+                            group.setQuestionList(questionService.findByExamAndSubjectAndObjectiveAndGroupNumber(examId,
+                                    subject.getCode(), false, group.getNumber()));
+                            groupMap.put(groupKey, group);
+                        }
+                        s.setGroupName(group.getQuestionTitle());
+                        s.setGroupNumber(m.getGroupNumber());
+                        s.setRole(Role.MARKER.getName());
+                        User u = userService.findById(m.getUserId());
+                        s.setLoginName(u.getLoginName());
+                        s.setRandomPassword(u.getRandomPassword());
+                        s.setCollege(collegeMap.get(m.getSubjectCode()));
+                        list.add(s);
+                    }
+                    if (list.isEmpty()) {
+                        continue;
+                    }
+                    ByteArrayOutputStream os = new ByteArrayOutputStream();
+                    new ExportExcel(query.getRole().getName() + "数据", MarkerDTO.class).setDataList(list).write(os);
+                    os.flush();
+                    byte[] bytes = os.toByteArray();
+                    writer.write(new ByteArrayInputStream(bytes),
+                            subjectName + "-" + query.getRole().getName() + ".xlsx");
+                }
+                if (query.getRole() != null
+                        && (query.getRole().equals(Role.SUBJECT_HEADER) || query.getRole().equals(Role.INSPECTOR))) {
+                    List<SubjectUserDTO> list = new ArrayList<SubjectUserDTO>();
+                    List<SubjectUser> subjectUsers = subjectUserService.findBySubjectCode(subject.getCode());
+                    for (SubjectUser subjectUser : subjectUsers) {
+                        User u = userService.findById(subjectUser.getUserId());
+                        if (!u.getRole().equals(query.getRole())) {
+                            continue;
+                        }
+                        SubjectUserDTO s = new SubjectUserDTO();
+                        s.setRole(query.getRole().getName());
+                        s.setLoginName(u.getLoginName());
+                        s.setRandomPassword(u.getRandomPassword());
+                        if (collegeMap.get(subject.getCode()) == null) {
+                            List<String> colleges = studentService.findDistinctCollegeBySubjectCode(examId,
+                                    subjectUser.getSubjectCode());
+                            collegeMap.put(subjectUser.getSubjectCode(), StringUtils.join(colleges, SPLIT));
+                        }
+                        s.setSubjectCode(subjectUser.getSubjectCode());
+                        s.setSubjectName(subject.getName());
+                        s.setCollege(collegeMap.get(subjectUser.getSubjectCode()));
+                        list.add(s);
+                    }
+                    if (list.isEmpty()) {
+                        continue;
+                    }
+                    ByteArrayOutputStream os = new ByteArrayOutputStream();
+                    new ExportExcel(query.getRole().getName() + "数据", SubjectUserDTO.class).setDataList(list).write(os);
+                    os.flush();
+                    byte[] bytes = os.toByteArray();
+                    writer.write(new ByteArrayInputStream(bytes),
+                            subjectName + "-" + query.getRole().getName() + ".xlsx");
+                }
+            }
+            writer.close();
+            return null;
+        } catch (Exception e) {
+            addMessage(redirectAttributes, "导出用户数据失败!" + e.getMessage());
+        }
+        return "redirect:/admin/user/list";
+    }
+
     @Logging(menu = "用户启用/禁用", type = LogType.UPDATE)
     @RequestMapping("/toggle")
     @RoleRequire({ Role.SCHOOL_ADMIN, Role.SUBJECT_HEADER, Role.COLLEGE_ADMIN })

+ 10 - 0
stmms-web/src/main/java/cn/com/qmth/stmms/admin/vo/ScanInfoVO.java

@@ -16,6 +16,9 @@ public class ScanInfoVO {
     @ExcelField(title = "已扫人数", align = 2, sort = 40)
     private long scanCount;
 
+    @ExcelField(title = "人工指定缺考", align = 2, sort = 50)
+    private long manualAbsentCount;
+
     public String getName() {
         return name;
     }
@@ -48,4 +51,11 @@ public class ScanInfoVO {
         this.scanSheetCount = scanSheetCount;
     }
 
+    public long getManualAbsentCount() {
+        return manualAbsentCount;
+    }
+
+    public void setManualAbsentCount(long manualAbsentCount) {
+        this.manualAbsentCount = manualAbsentCount;
+    }
 }

+ 1 - 1
stmms-web/src/main/java/cn/com/qmth/stmms/api/controller/CoreController.java

@@ -538,7 +538,7 @@ public class CoreController extends BaseApiController {
             subject.setUploadCount(0);
             subject.setAutoScroll(exam.isAutoScroll());
             subject.setEnableSplit(exam.isEnableSplit());
-            subject.setDisplayQuestionName(false);
+            subject.setDisplayQuestionName(true);
             subject.setInspectRound(1);
             subject.setSelective(false);
         }

+ 2 - 6
stmms-web/src/main/java/cn/com/qmth/stmms/api/controller/ExamStudentController.java

@@ -185,9 +185,7 @@ public class ExamStudentController extends BaseApiController {
                 obj.accumulate("college", StringUtils.trimToEmpty(student.getCollege()));
                 obj.accumulate("className", StringUtils.trimToEmpty(student.getClassName()));
                 obj.accumulate("teacher", StringUtils.trimToEmpty(student.getTeacher()));
-                if (student.getInspectorId() != null) {
-                    obj.accumulate("inspector", getInspector(student.getId()));
-                }
+                obj.accumulate("inspector", getInspector(student.getId()));
 
                 try {
                     if (withScoreDetail != null && withScoreDetail.booleanValue()) {
@@ -459,9 +457,7 @@ public class ExamStudentController extends BaseApiController {
                 obj.accumulate("college", StringUtils.trimToEmpty(student.getCollege()));
                 obj.accumulate("className", StringUtils.trimToEmpty(student.getClassName()));
                 obj.accumulate("teacher", StringUtils.trimToEmpty(student.getTeacher()));
-                if (student.getInspectorId() != null) {
-                    obj.accumulate("inspector", getInspector(student.getId()));
-                }
+                obj.accumulate("inspector", getInspector(student.getId()));
 
                 try {
                     if (withScoreDetail != null && withScoreDetail.booleanValue()) {

+ 5 - 3
stmms-web/src/main/webapp/WEB-INF/views/modules/exam/groupAdd.jsp

@@ -115,27 +115,29 @@
                 </caption>
                 <thead>
                 <tr>
+                    <th></th>
                     <th>大题号</th>
                     <th>小题号</th>
                     <th>名称</th>
+                    <th>昵称</th>
                     <th>分数</th>
                     <th>是否选做题</th>
                     <th>选做题分组</th>
                     <th>选做题区</th>
-                    <th></th>
                 </tr>
                 </thead>
                 <c:forEach items="${questionList}" var="item">
                     <tr>
+                        <td><input type="checkbox" name="questionIds" value="${item.id }" <c:if
+                                test="${item.groupNumber!=null}"> disabled="disabled"</c:if>></td>
                         <td>${item.mainNumber }</td>
                         <td>${item.subNumber }</td>
                         <td>${item.mainTitle }</td>
+                        <td>${item.name }</td>
                         <td><fmt:formatNumber pattern="###.###" value="${item.totalScore}"/></td>
                         <td><c:if test="${item.selective }">选做题</c:if></td>
                         <td>${item.selectiveIndex}</td>
                         <td>${item.selectiveIndex}-${item.selectivePart}</td>
-                        <td><input type="checkbox" name="questionIds" value="${item.id }" <c:if
-                                test="${item.groupNumber!=null}"> disabled="disabled"</c:if>></td>
                     </tr>
                 </c:forEach>
             </table>

+ 7 - 5
stmms-web/src/main/webapp/WEB-INF/views/modules/exam/groupEditFull.jsp

@@ -256,29 +256,31 @@
                 </caption>
                 <thead>
                 <tr>
+                    <th></th>
                     <th>大题号</th>
                     <th>小题号</th>
                     <th>名称</th>
+                    <th>昵称</th>
                     <th>分数</th>
                     <th>是否选做题</th>
                     <th>选做题分组</th>
                     <th>选做题区</th>
-                    <th></th>
                 </tr>
                 </thead>
                 <c:forEach items="${questionList}" var="item">
                     <tr>
+                        <td><input type="checkbox" name="questionIds" value="${item.id }"
+                        <c:if test="${item.groupNumber!=null && item.groupNumber!=group.number}">
+                                       disabled="disabled"</c:if> <c:if test="${item.groupNumber==group.number}">
+                                   checked</c:if>></td>
                         <td>${item.mainNumber }</td>
                         <td>${item.subNumber }</td>
                         <td>${item.mainTitle }</td>
+                        <td>${item.name }</td>
                         <td><fmt:formatNumber pattern="###.###" value="${item.totalScore}"/></td>
                         <td><c:if test="${item.selective }">选做题</c:if></td>
                         <td>${item.selectiveIndex}</td>
                         <td>${item.selectiveIndex}-${item.selectivePart}</td>
-                        <td><input type="checkbox" name="questionIds" value="${item.id }"
-                        <c:if test="${item.groupNumber!=null && item.groupNumber!=group.number}">
-                                   disabled="disabled"</c:if> <c:if test="${item.groupNumber==group.number}">
-                                   checked</c:if>></td>
                     </tr>
                 </c:forEach>
             </table>

+ 8 - 0
stmms-web/src/main/webapp/WEB-INF/views/modules/exam/problemHistory.jsp

@@ -55,6 +55,8 @@
         <c:if test="${fnx:hasPrivilegeCode(role_privilege_codes, 'exam_problem_history-batch_reset') && query.status=='WAITING'}">
         <input id="btnRest" class="btn" type="button" value="批量重置" onclick="goRest()"/>
         </c:if>
+
+        <input id="btnExport" class="btn btn-primary" type="button" value="导出" onclick="goExport()"/>
     </div>
 </form>
 <tags:message content="${message}"/>
@@ -199,6 +201,12 @@
         $("#searchForm").submit();
         return false;
     }
+
+    function goExport() {
+        $("#searchForm").attr("action", "${ctx}/admin/exam/problem/history/export");
+        $("#searchForm").submit();
+    }
+
     $("#checkAll").change(function () {
         if ($("#checkAll").is(':checked')) {
             $(".libraryIds").attr("checked", true);

+ 3 - 1
stmms-web/src/main/webapp/WEB-INF/views/modules/exam/scanInfo.jsp

@@ -90,6 +90,7 @@
 				<th>考生总数</th>
 				<th>已扫张数</th>
 				<th>已扫人数</th>
+				<th>人工指定缺考</th>
 				<th>进度</th>
 			</tr>
 		</thead>
@@ -100,12 +101,13 @@
 				<td>${info.totalCount}</td>
 				<td>${info.scanSheetCount}</td>
 				<td>${info.scanCount}</td>
+				<td>${info.manualAbsentCount}</td>
 				<td>
 					<c:if test="${info.totalCount==0}">
 						0%
 					</c:if>
 					<c:if test="${info.totalCount>0}">
-						<fmt:formatNumber type="PERCENT" value="${info.scanCount/info.totalCount}"/>
+						<fmt:formatNumber type="PERCENT" value="${(info.scanCount+info.manualAbsentCount)/info.totalCount}"/>
 					</c:if>
 				</td>
 			</tr>

+ 11 - 1
stmms-web/src/main/webapp/WEB-INF/views/modules/user/userList.jsp

@@ -101,7 +101,8 @@
 				</a>
 				<ul class="dropdown-menu">
 					<li><a href="##" onclick="goExport()">导出</a></li>
-					<li><a href="##" onclick="goExportExam()">按考试导出</a></li>
+					<li><a href="##" onclick="goExportExam()">按考试导出全部</a></li>
+                    <li><a href="##" onclick="goExportSubject()">按考试导出科目分表</a></li>
 				</ul>
 			</div>
 			 &nbsp;
@@ -300,6 +301,15 @@
         $("#exportForm").attr("action", "${ctx}/admin/user/exportExam");
         $("#exportForm").submit();
     }
+    function goExportSubject() {
+        var roleId= $('#roleId').val();
+        if(roleId!="4" && roleId!="5" && roleId!="8"){
+            alert("请选择角色,查询后导出");
+            return false;
+        }
+        $("#exportForm").attr("action", "${ctx}/admin/user/exportSubject");
+        $("#exportForm").submit();
+    }
     $("#ids").change(function () {
         if ($("#ids").is(':checked')) {
             $(".ids").attr("checked", true);