1
0
Эх сурвалжийг харах

exam增加强制标记,group双评属性修改

ting.yin 6 жил өмнө
parent
commit
b866e87e7e
25 өөрчлөгдсөн 935 нэмэгдсэн , 236 устгасан
  1. 13 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/Exam.java
  2. 9 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/MarkGroup.java
  3. 9 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/Impl/MarkServiceImpl.java
  4. 7 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/MarkService.java
  5. 2 2
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/dto/SubjectiveQuestionDTO.java
  6. 15 2
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/ExamController.java
  7. 5 1
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/LibraryController.java
  8. 28 3
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/MarkGroupController.java
  9. 20 17
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/MarkTrackController.java
  10. 10 2
      stmms-web/src/main/java/cn/com/qmth/stmms/mark/MarkController.java
  11. 82 0
      stmms-web/src/main/webapp/WEB-INF/views/modules/exam/examEdit.jsp
  12. 19 1
      stmms-web/src/main/webapp/WEB-INF/views/modules/exam/examForm.jsp
  13. 5 0
      stmms-web/src/main/webapp/WEB-INF/views/modules/exam/examList.jsp
  14. 39 0
      stmms-web/src/main/webapp/WEB-INF/views/modules/exam/groupAdd.jsp
  15. 51 0
      stmms-web/src/main/webapp/WEB-INF/views/modules/exam/groupEditFull.jsp
  16. 41 0
      stmms-web/src/main/webapp/WEB-INF/views/modules/exam/groupEditSimple.jsp
  17. 1 1
      stmms-web/src/main/webapp/WEB-INF/views/modules/exam/libraryList.jsp
  18. 1 1
      stmms-web/src/main/webapp/WEB-INF/views/modules/exam/scoreList.jsp
  19. 8 2
      stmms-web/src/main/webapp/WEB-INF/views/modules/mark/markNew.jsp
  20. 43 2
      stmms-web/src/main/webapp/static/mark-new/css/style.css
  21. 42 1
      stmms-web/src/main/webapp/static/mark-new/js/mark-control.js
  22. 2 0
      stmms-web/src/main/webapp/static/mark-new/js/modules/mark-history.js
  23. 250 0
      stmms-web/src/main/webapp/static/mark-new/js/modules/simple-image-view.js
  24. 69 201
      stmms-web/src/main/webapp/static/mark-new/js/modules/single-image-view.js
  25. 164 0
      stmms-web/src/main/webapp/static/mark-new/js/modules/specialTag.js

+ 13 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/Exam.java

@@ -52,6 +52,11 @@ public class Exam implements Serializable {
 
     @Column(name = "creator_id")
     private Integer creatorId;
+    /**
+     * 开启强制特殊标记
+     */
+    @Column(name = "force_special_tag",nullable = false)
+    private boolean forceSpecialTag;
 
     public Integer getId() {
         return id;
@@ -125,4 +130,12 @@ public class Exam implements Serializable {
         this.schoolId = schoolId;
     }
 
+	public boolean isForceSpecialTag() {
+		return forceSpecialTag;
+	}
+
+	public void setForceSpecialTag(boolean forceSpecialTag) {
+		this.forceSpecialTag = forceSpecialTag;
+	}
+
 }

+ 9 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/MarkGroup.java

@@ -39,12 +39,21 @@ public class MarkGroup implements Serializable {
     @Column(name = "total_score", nullable = false)
     private Double totalScore;
 
+    /**
+     * 双评比例(0~1)
+     */
     @Column(name = "double_rate", nullable = true)
     private Double doubleRate;
 
+    /**
+     * 仲裁阀值
+     */
     @Column(name = "arbitrate_threshold", nullable = true)
     private Double arbitrateThreshold;
 
+    /**
+     * 合分策略(1-平均,2-最高,3-最低)
+     */
     @Column(name = "score_policy", nullable = true)
     @Enumerated(EnumType.STRING)
     private ScorePolicy scorePolicy;

+ 9 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/Impl/MarkServiceImpl.java

@@ -477,6 +477,7 @@ public class MarkServiceImpl implements MarkService {
      * @param subjectCode
      * @param groupNumber
      */
+    @Transactional
     @Override
     public void updateLibraryCount(Integer examId, String subjectCode) {
         groupDao.updateLibraryCount(examId, subjectCode);
@@ -536,4 +537,12 @@ public class MarkServiceImpl implements MarkService {
         return library.getStudentId() + "_" + library.getGroupNumber();
     }
 
+    @Transactional
+	@Override
+	public void updateGroupScorePolicy(MarkGroup group, Integer scorePolicy) {
+		group.setScorePolicy(ScorePolicy.findByValue(scorePolicy));
+		groupDao.save(group);
+		resetByGroup(group);
+	}
+
 }

+ 7 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/MarkService.java

@@ -162,4 +162,11 @@ public interface MarkService {
      */
     void buildLibrary(ExamStudent student, Campus campus, MarkGroup group);
 
+    /**
+     * 更新某个大题判分策略并重置
+     * @param group
+     * @param scorePolicy
+     */
+	void updateGroupScorePolicy(MarkGroup group, Integer scorePolicy);
+
 }

+ 2 - 2
stmms-web/src/main/java/cn/com/qmth/stmms/admin/dto/SubjectiveQuestionDTO.java

@@ -56,8 +56,8 @@ public class SubjectiveQuestionDTO implements QuestionDTO {
         setTotalScore(question.getTotalScore());
         setIntervalScore(question.getIntervalScore());
         setPicList(group != null ? group.getPicList() : "");
-        setDoubleRate(group != null ? group.getDoubleRate() : 0d);
-        setArbitrateThreshold(group != null ? group.getArbitrateThreshold() : 0d);
+        setDoubleRate(group != null && group.getDoubleRate() !=null ? group.getDoubleRate() : 0d);
+        setArbitrateThreshold(group != null && group.getArbitrateThreshold() !=null? group.getArbitrateThreshold() : 0d);
         setScorePolicy(group != null && group.getScorePolicy() != null ? group.getScorePolicy().getValue()
                 : ScorePolicy.AVG.getValue());
     }

+ 15 - 2
stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/ExamController.java

@@ -14,6 +14,7 @@ import org.springframework.ui.Model;
 import org.springframework.web.bind.annotation.PathVariable;
 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.bind.annotation.ResponseBody;
 import org.springframework.web.servlet.mvc.support.RedirectAttributes;
 
@@ -71,9 +72,19 @@ public class ExamController extends BaseExamController {
     @RoleRequire(Role.SCHOOL_ADMIN)
     public String add(Exam exam, Model model) {
         model.addAttribute("exam", exam);
+        model.addAttribute("statusList", ExamStatus.values());
         return "modules/exam/examForm";
     }
-
+    
+    @RequestMapping("/exam-edit/{examId}")
+    @RoleRequire(Role.SCHOOL_ADMIN)
+    public String edit(@PathVariable Integer examId, Model model) {
+    	Exam exam = examService.findById(examId);
+        model.addAttribute("exam", exam);
+        model.addAttribute("statusList", ExamStatus.values());
+        return "modules/exam/examEdit";
+    }
+    
     @RequestMapping(value = "/exam-save", method = RequestMethod.POST)
     @RoleRequire(Role.SCHOOL_ADMIN)
     public String save(HttpServletRequest request, Exam exam, RedirectAttributes redirectAttributes) {
@@ -88,13 +99,15 @@ public class ExamController extends BaseExamController {
 
     @RequestMapping(value = "/exam-edit", method = RequestMethod.POST)
     @RoleRequire(Role.SCHOOL_ADMIN)
-    public String examEdit(HttpServletRequest request, Exam exam) {
+    public String examEdit(HttpServletRequest request,Exam exam,int StatusValue, RedirectAttributes redirectAttributes) {
         User user = RequestUtils.getWebUser(request).getUser();
         Exam oldExam = examService.findById(exam.getId());
         if (oldExam != null && oldExam.getCreatorId().intValue() == user.getId().intValue()) {
             oldExam.setName(exam.getName());
             oldExam.setExamTime(exam.getExamTime());
             oldExam.setDescription(exam.getDescription());
+            oldExam.setStatus(ExamStatus.findByValue(StatusValue));
+            oldExam.setForceSpecialTag(exam.isForceSpecialTag());
             examService.save(oldExam);
         }
         return "redirect:/admin/exam-list";

+ 5 - 1
stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/LibraryController.java

@@ -49,7 +49,7 @@ public class LibraryController extends BaseExamController {
     private MarkService markService;
 
     @RequestMapping
-    public String list(Model model, HttpServletRequest request, MarkLibrarySearchQuery query) {
+    public String list(Model model, HttpServletRequest request, MarkLibrarySearchQuery query,LibraryStatus status) {
         int examId = getSessionExamId(request);
         WebUser wu = RequestUtils.getWebUser(request);
         List<ExamSubject> subjectList = getExamSubject(examId, wu);
@@ -68,6 +68,9 @@ public class LibraryController extends BaseExamController {
         if (query.getGroupNumber() == 0) {
             query.setGroupNumber(groupList.get(0).getNumber());
         }
+        if (status!=null) {
+            query.addStatus(status);
+        }
         query = libraryService.findByQuery(query);
         for (MarkLibrary library : query.getResult()) {
             if (library.getMarkerId() != null) {
@@ -78,6 +81,7 @@ public class LibraryController extends BaseExamController {
         model.addAttribute("subjectList", subjectList);
         model.addAttribute("groupList", groupList);
         model.addAttribute("statusList", LibraryStatus.values());
+        model.addAttribute("status", status);
         model.addAttribute("markerList",
                 markerService.findByExamAndSubjectAndGroup(examId, query.getSubjectCode(), query.getGroupNumber()));
         return "modules/exam/libraryList";

+ 28 - 3
stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/MarkGroupController.java

@@ -39,6 +39,7 @@ import cn.com.qmth.stmms.biz.mark.service.MarkService;
 import cn.com.qmth.stmms.common.auth.annotation.RoleRequire;
 import cn.com.qmth.stmms.common.domain.WebUser;
 import cn.com.qmth.stmms.common.enums.Role;
+import cn.com.qmth.stmms.common.enums.ScorePolicy;
 import cn.com.qmth.stmms.common.utils.PictureUrlBuilder;
 import cn.com.qmth.stmms.common.utils.RequestUtils;
 import net.sf.json.JSONArray;
@@ -178,6 +179,7 @@ public class MarkGroupController extends BaseExamController {
         MarkGroup group = new MarkGroup();
         group.setSubjectCode(subjectCode);
         model.addAttribute("group", group);
+        model.addAttribute("scorePolicyList", ScorePolicy.values());
         return "modules/exam/groupAdd";
     }
 
@@ -188,10 +190,13 @@ public class MarkGroupController extends BaseExamController {
         int examId = getSessionExamId(request);
         MarkGroup group = groupService.findOne(examId, subjectCode, number);
         if (group != null) {
+        	String pictureConfig = buildPictureConfig(group);
+        	group.setPicList(pictureConfig);
             model.addAttribute("group", group);
             model.addAttribute("questions", questionService.findByExamAndSubjectAndObjectiveAndMainNumber(
                     group.getExamId(), group.getSubjectCode(), false, group.getNumber()));
-            model.addAttribute("pictureConfig", buildPictureConfig(group));
+            model.addAttribute("pictureConfig", pictureConfig);
+            model.addAttribute("scorePolicyList", ScorePolicy.values());
             return "modules/exam/groupEditSimple";
         } else {
             redirectAttributes.addAttribute("subjectCode", subjectCode);
@@ -206,10 +211,13 @@ public class MarkGroupController extends BaseExamController {
         int examId = getSessionExamId(request);
         MarkGroup group = groupService.findOne(examId, subjectCode, number);
         if (group != null) {
+        	String pictureConfig = buildPictureConfig(group);
+        	group.setPicList(pictureConfig);
             group.setScoreList(
                     questionService.findByExamAndSubjectAndObjectiveAndMainNumber(examId, subjectCode, false, number));
             model.addAttribute("group", group);
-            model.addAttribute("pictureConfig", buildPictureConfig(group));
+            model.addAttribute("pictureConfig", pictureConfig);
+            model.addAttribute("scorePolicyList", ScorePolicy.values());
             return "modules/exam/groupEditFull";
         } else {
             redirectAttributes.addAttribute("subjectCode", subjectCode);
@@ -238,7 +246,10 @@ public class MarkGroupController extends BaseExamController {
             @RequestParam String subjectCode, @RequestParam Integer number,
             @RequestParam(required = false) String title, @RequestParam(required = false) String picList,
             @RequestParam(required = false) String intervalScoreList,
-            @RequestParam(required = false) String scoreList) {
+            @RequestParam(required = false) String scoreList,
+            @RequestParam(required = false) Double doubleRate,
+            @RequestParam(required = false) Double arbitrateThreshold,
+            @RequestParam(required = false) Integer scorePolicy ) {
         int examId = getSessionExamId(request);
         MarkGroup group = groupService.findOne(examId, subjectCode, number);
         List<ExamQuestion> questionList = questionService.findByExamAndSubjectAndObjectiveAndMainNumber(examId,
@@ -264,11 +275,21 @@ public class MarkGroupController extends BaseExamController {
             if (title != null) {
                 groupService.updateTitle(examId, subjectCode, number, title);
             }
+            if (doubleRate != null) {
+            	group.setDoubleRate(doubleRate);
+            }
+            if (arbitrateThreshold != null) {
+            	group.setArbitrateThreshold(arbitrateThreshold);
+            }
+            groupService.save(group);
             // advance update
             List<Double> scores = buildDoubleList(scoreList);
             if (scores.size() > 0) {
                 markService.updateGroupScore(group, scores);
             }
+            if(scorePolicy!=null && !ScorePolicy.findByValue(scorePolicy).equals(group.getScorePolicy())){
+            	markService.updateGroupScorePolicy(group, scorePolicy);
+            }
             redirectAttributes.addAttribute("subjectCode", subjectCode);
             redirectAttributes.addAttribute("number", number);
             return "redirect:/admin/exam/group";
@@ -295,6 +316,10 @@ public class MarkGroupController extends BaseExamController {
             addMessage(redirectAttributes, "大题号不能重复");
             redirectAttributes.addAttribute("subjectCode", subjectCode);
             return "redirect:/admin/exam/group/add";
+        } else if (StringUtils.isBlank(picList)) {
+            addMessage(redirectAttributes, "图片范围必须设置");
+            redirectAttributes.addAttribute("subjectCode", subjectCode);
+            return "redirect:/admin/exam/group/add";
         } else {
             // create group
             picList = StringEscapeUtils.unescapeHtml(picList);

+ 20 - 17
stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/MarkTrackController.java

@@ -64,26 +64,29 @@ public class MarkTrackController extends BaseExamController {
     @RequestMapping
     public HashMap<String, Object> list(Integer studentId) {
         List<MarkLibrary> librarys = libraryService.findByStudentId(studentId);
+        ExamStudent examStudent = studentService.findById(studentId);
+        Campus campus = campusService.findBySchoolAndName(examStudent.getSchoolId(), examStudent.getCampusName());
         List<Object> list = new ArrayList<Object>();
         HashMap<String, Object> map = new HashMap<String, Object>();
         for (MarkLibrary library : librarys) {
-            ExamStudent examStudent = studentService.findById(library.getStudentId());
-            Campus campus = campusService.findBySchoolAndName(examStudent.getSchoolId(), examStudent.getCampusName());
-            MarkGroup group = groupService.findOne(examStudent.getExamId(), examStudent.getSubjectCode(),
-                    library.getGroupNumber());
-            List<String> picUrls = PictureUrlBuilder.getSliceUrls(examStudent.getExamId(), campus.getId(),
-                    examStudent.getSubjectCode(), examStudent.getExamNumber(), examStudent.getSliceCount());
-            List<MarkTrack> markTracks = markTrackService.findByStudentIdAndGroupNumber(library.getStudentId(),
-                    group.getNumber());
-            HashMap<String, Object> groups = new HashMap<String, Object>();
-            List<MarkSpecialTag> markSpecialTagList = markSpecialTagService.findByLibraryId(library.getId());
-            groups.put("picUrls", picUrls);
-            groups.put("pictureConfig", group.getPictureConfigList());
-            groups.put("markTracks", markTracks);
-            groups.put("groupTitle", group.getTitle());
-            groups.put("groupNumber", group.getNumber());
-            groups.put("markSpecialTagList", markSpecialTagList);
-            list.add(groups);
+        	if(null!=library.getTaskNumber() && library.getTaskNumber()==2){
+        		continue;
+        	}
+	            MarkGroup group = groupService.findOne(examStudent.getExamId(), examStudent.getSubjectCode(),
+	                    library.getGroupNumber());
+	            List<String> picUrls = PictureUrlBuilder.getSliceUrls(examStudent.getExamId(), campus.getId(),
+	                    examStudent.getSubjectCode(), examStudent.getExamNumber(), examStudent.getSliceCount());
+	            List<MarkTrack> markTracks = markTrackService.findByStudentIdAndGroupNumber(library.getStudentId(),
+	                    group.getNumber());
+	            HashMap<String, Object> groups = new HashMap<String, Object>();
+	            List<MarkSpecialTag> markSpecialTagList = markSpecialTagService.findByLibraryId(library.getId());
+	            groups.put("picUrls", picUrls);
+	            groups.put("pictureConfig", group.getPictureConfigList());
+	            groups.put("markTracks", markTracks);
+	            groups.put("groupTitle", group.getTitle());
+	            groups.put("groupNumber", group.getNumber());
+	            groups.put("markSpecialTagList", markSpecialTagList);
+	            list.add(groups);
         }
         map.put("list", list);
         map.put("imageServer", imageServer);

+ 10 - 2
stmms-web/src/main/java/cn/com/qmth/stmms/mark/MarkController.java

@@ -7,6 +7,9 @@ import java.util.Set;
 
 import javax.servlet.http.HttpServletRequest;
 
+import net.sf.json.JSONArray;
+import net.sf.json.JSONObject;
+
 import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -20,9 +23,11 @@ import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.ResponseBody;
 import org.springframework.web.servlet.ModelAndView;
 
+import cn.com.qmth.stmms.biz.exam.model.Exam;
 import cn.com.qmth.stmms.biz.exam.model.ExamSubject;
 import cn.com.qmth.stmms.biz.exam.model.Marker;
 import cn.com.qmth.stmms.biz.exam.model.Tag;
+import cn.com.qmth.stmms.biz.exam.service.ExamService;
 import cn.com.qmth.stmms.biz.exam.service.ExamSubjectService;
 import cn.com.qmth.stmms.biz.exam.service.MarkerService;
 import cn.com.qmth.stmms.biz.exam.service.TagService;
@@ -37,8 +42,6 @@ import cn.com.qmth.stmms.common.enums.ExamSubjectStatus;
 import cn.com.qmth.stmms.common.enums.LibraryStatus;
 import cn.com.qmth.stmms.common.session.model.StmmsSession;
 import cn.com.qmth.stmms.common.utils.RequestUtils;
-import net.sf.json.JSONArray;
-import net.sf.json.JSONObject;
 
 @Controller
 @RequestMapping("/mark")
@@ -63,6 +66,9 @@ public class MarkController extends BaseController {
 
     @Autowired
     private MarkService markService;
+    
+    @Autowired
+    private ExamService examService;
 
     @Value("${slice.image.server}")
     private String sliceServer;
@@ -158,6 +164,8 @@ public class MarkController extends BaseController {
         modelAndView.addObject("cardServer", cardServer);
         modelAndView.addObject("marker", marker);
         modelAndView.addObject("subject", subjectService.find(marker.getExamId(), marker.getSubjectCode()));
+        Exam exam = examService.findById(marker.getExamId());
+        modelAndView.addObject("forceSpecialTag",exam.isForceSpecialTag() );
         markService.releaseByMarker(marker);
     }
 

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

@@ -0,0 +1,82 @@
+<%@ 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" %>
+	<script type="text/javascript">
+		$(document).ready(function() {
+			$("#name").focus();
+			$("#inputForm").validate({
+				submitHandler: function(form){
+					loading('正在提交,请稍等...');
+					form.submit();
+				},
+				errorContainer: "#messageBox",
+				errorPlacement: function(error, element) {
+					$("#messageBox").text("输入有误,请先更正。");
+					if (element.is(":checkbox")||element.is(":radio")||element.parent().is(".input-append")){
+						error.appendTo(element.parent().parent());
+					} else {
+						error.insertAfter(element);
+					}
+				}
+			});
+		});
+	</script>
+</head>
+<body>
+	<ul class="nav nav-tabs">
+		<li><a href="${ctx}/admin/exam-list">考试列表</a></li>
+		<li class="active"><a href="##">编辑考试</a></li>
+	</ul><br/>
+	<form:form id="inputForm" modelAttribute="exam" action="${ctx}/admin/exam-edit" method="post" class="form-horizontal">
+		<form:hidden path="id"/>
+		<tags:message content="${message}"/>
+		<div class="control-group">
+			<label class="control-label">考试名称</label>
+			<div class="controls">
+				<form:input path="name" htmlEscape="false" maxlength="200" class="required"/>
+			</div>
+		</div>
+		<div class="control-group">
+			<label class="control-label">考试日期</label>
+			<div class="controls">
+				<input name="examTime" type="text" readonly="readonly" maxlength="20" class="Wdate required"
+					value="${exam.examTime }"
+					onclick="WdatePicker({dateFmt:'yyyy-MM-dd',isShowClear:true});"/>
+			</div>
+		</div>
+		<div class="control-group">
+			<label class="control-label">强制标记</label>
+			<div class="controls">
+				<input name="forceSpecialTag" type="checkbox" <c:if test="${exam.forceSpecialTag}">checked</c:if>/>
+			</div>
+		</div>
+		<c:if test="${exam.id!=null }">
+		<div class="control-group">
+			<label class="control-label">状态</label>
+			<div class="controls">
+				<select class="input-small" name="StatusValue">
+                <c:forEach items="${statusList}" var="item">
+                	 <option value="${item.value}" <c:if test="${item.value==exam.status.value}">selected</c:if>>${item.name}</option>
+                </c:forEach>
+            </select>
+			</div>
+		</div>
+		</c:if>
+		<div class="control-group">
+			<label class="control-label">描述</label>
+			<div class="controls">
+				<form:textarea path="description" htmlEscape="false" rows="4" maxlength="200" class="input-xxlarge"/>
+			</div>
+		</div>
+		<div class="form-actions">
+			<input id="btnSubmit" class="btn btn-primary" type="submit" value="保 存"/>
+			&nbsp;
+			<a href="${ctx}/admin/exam-list" class="btn"/>返回</a>
+		</div>
+	</form:form>
+</body>
+</html>

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

@@ -43,10 +43,28 @@
 			<label class="control-label">考试日期</label>
 			<div class="controls">
 				<input name="examTime" type="text" readonly="readonly" maxlength="20" class="Wdate required"
-					value=""
+					value="${exam.examTime }"
 					onclick="WdatePicker({dateFmt:'yyyy-MM-dd',isShowClear:true});"/>
 			</div>
 		</div>
+		<div class="control-group">
+			<label class="control-label">强制标记</label>
+			<div class="controls">
+				<input name="forceSpecialTag" type="checkbox" <c:if test="${exam.forceSpecialTag}">checked</c:if>/>
+			</div>
+		</div>
+		<c:if test="${exam.id!=null }">
+		<div class="control-group">
+			<label class="control-label">状态</label>
+			<div class="controls">
+				<select class="input-small" name="status">
+                <c:forEach items="${statusList}" var="item">
+                	 <option value="${item.value}" <c:if test="${item.value==exam.status.value}">selected</c:if>>${item.name}</option>
+                </c:forEach>
+            </select>
+			</div>
+		</div>
+		</c:if>
 		<div class="control-group">
 			<label class="control-label">描述</label>
 			<div class="controls">

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

@@ -32,6 +32,7 @@
 				<th>编号</th>
 				<th>考试名称</th>
 				<th>考试时间</th>
+				<th>强制标记</th>
 				<th>状态</th>
 				<th>操作</th>
 			</tr>
@@ -42,9 +43,13 @@
 				<td>${exam.id}</td>
 				<td><a href="${ctx}/admin/exam-select/${exam.id}">${exam.name}</a></td>
 				<td><fmt:formatDate value="${exam.examTime}" pattern="yyyy-MM-dd" /></td>
+				<td><c:if test="${exam.forceSpecialTag}">是</c:if>
+					<c:if test="${!exam.forceSpecialTag}">否</c:if>
+				</td>
 				<td>${exam.status.name}</td>
 				<td>
     				<a href="${ctx}/admin/exam-view/${exam.id}">详情</a>
+    				<a href="${ctx}/admin/exam-edit/${exam.id}">编辑</a>
 				</td>
 			</tr>
 		</c:forEach>

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

@@ -24,6 +24,15 @@
 					}
 				}
 			});
+			$(".doubleDiv").hide();
+			$("#openDouble").change(function() { 
+				if ($("#openDouble").is(':checked')){
+					$(".doubleDiv").show();
+				}else{
+					$(".doubleDiv").hide();
+				}
+
+			});
 		});
 	</script>
 </head>
@@ -58,6 +67,36 @@
                 <form:input path="picList" class="required" id="picList"  type="hidden"/>
                 <a href="${ctx}/admin/exam/group/getPictureConfig?subjectCode=${group.subjectCode}&number=${group.number}" target="_blank" class="required" id= "configuration">设置</a>
             </div>
+        </div>
+		<div class="control-group">
+            <label class="control-label">双评</label>
+            <div class="controls">
+                <input type="checkbox" id="openDouble">开启
+            </div>
+        </div>
+        <div  class="doubleDiv">
+        <div class="control-group">
+            <label class="control-label">双评比例</label>
+            <div class="controls">
+                <form:input path="doubleRate" htmlEscape="false" maxlength="100" class="required" type="number"/>*比例范围为0-1
+            </div>
+        </div>
+        <div class="control-group">
+            <label class="control-label">仲裁阀值</label>
+            <div class="controls">
+                <form:input path="arbitrateThreshold" htmlEscape="false" maxlength="100" class="required" type="number"/>*阈值为分数
+            </div>
+        </div>
+        <div class="control-group">
+            <label class="control-label">合分策略</label>
+            <div class="controls">
+				<select name="scorePolicy">
+	                <c:forEach items="${scorePolicyList}" var="item">
+	                	 <option value="${item.value}" >${item.name}</option>
+	                </c:forEach>
+	            </select>
+            </div>
+        </div>
         </div>
         <div class="form-actions">
             <input id="btnSubmit" class="btn btn-primary" type="submit" value="保 存"/>&nbsp;

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

@@ -25,6 +25,27 @@
 					}
 				}
 			});
+			var openDouble = "${group.doubleRate}";
+			if(openDouble!=null&&openDouble>0){
+				$("#openDouble").attr("checked","checked");
+				$("#openDouble").attr("disabled","disabled");
+				$(".doubleDiv").show();
+			}else{
+				$(".doubleDiv").hide();
+				$("#doubleRate").value = null;
+				$("#arbitrateThreshold").value = null;
+			}
+			
+			$("#openDouble").change(function() { 
+				if ($("#openDouble").is(':checked')){
+					$(".doubleDiv").show();
+				}else{
+					$(".doubleDiv").hide();
+					$("#doubleRate").value = null;
+					$("#arbitrateThreshold").value = null;
+				}
+
+			});
 		});
 	</script>
 </head>
@@ -61,6 +82,36 @@
             	<form:input path="picList" class="required" id="picList"  type="hidden"/>
                 <a href="${ctx}/admin/exam/group/getPictureConfig?subjectCode=${group.subjectCode}&number=${group.number}" target="_blank" class="required" id= "configuration">设置</a>
             </div>
+        </div>
+		<div class="control-group">
+            <label class="control-label">双评</label>
+            <div class="controls">
+                <input type="checkbox" id="openDouble">开启
+            </div>
+        </div>
+		<div  class="doubleDiv">
+        <div class="control-group">
+            <label class="control-label">双评比例</label>
+            <div class="controls">
+                <form:input path="doubleRate" htmlEscape="false" maxlength="100" class="required" type="number" id = "doubleRate"/>*比例范围为0-1
+            </div>
+        </div>
+        <div class="control-group">
+            <label class="control-label">仲裁阀值</label>
+            <div class="controls">
+                <form:input path="arbitrateThreshold" htmlEscape="false" maxlength="100" class="required" type="number" id="arbitrateThreshold"/>*阈值为分数
+            </div>
+        </div>
+        <div class="control-group">
+            <label class="control-label">合分策略</label>
+            <div class="controls">
+				<select name="scorePolicy">
+	                <c:forEach items="${scorePolicyList}" var="item">
+	                	 <option value="${item.value}"<c:if test="${item.value==group.scorePolicy.value}">selected</c:if> >${item.name}</option>
+	                </c:forEach>
+	            </select>
+            </div>
+        </div>
         </div>
         <div class="control-group">
             <label class="control-label">重要提示</label>

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

@@ -25,6 +25,27 @@
 					}
 				}
 			});
+			
+			var openDouble = "${group.doubleRate}";
+			if(openDouble!=null&&openDouble>0){
+				$("#openDouble").attr("checked","checked");
+				$(".doubleDiv").show();
+				$("#openDouble").attr("disabled","disabled");
+			}else{
+				$(".doubleDiv").hide();
+				$("#doubleRate").value = null;
+				$("#arbitrateThreshold").value = null;
+			}
+			$("#openDouble").change(function() { 
+				if ($("#openDouble").is(':checked')){
+					$(".doubleDiv").show();
+				}else{
+					$(".doubleDiv").hide();
+					$("#doubleRate").value = null;
+					$("#arbitrateThreshold").value = null;
+				}
+
+			});
 		});
 	</script>
 </head>
@@ -60,6 +81,26 @@
             </div>
         </div>
         </c:forEach>
+		<div class="control-group">
+            <label class="control-label">双评</label>
+            <div class="controls">
+                <input type="checkbox" id="openDouble">开启
+            </div>
+        </div>
+        <div  class="doubleDiv">
+        <div class="control-group">
+            <label class="control-label">双评比例</label>
+            <div class="controls">
+                <form:input path="doubleRate" htmlEscape="false" maxlength="100" class="required" type="number" id="doubleRate"/>*比例范围为0-1
+            </div>
+        </div>
+        <div class="control-group">
+            <label class="control-label">仲裁阀值</label>
+            <div class="controls">
+                <form:input path="arbitrateThreshold" htmlEscape="false" maxlength="100" class="required" type="number" id="arbitrateThreshold"/>*阈值为分数
+            </div>
+        </div>
+        </div>
         <div class="form-actions">
             <a id="btnSubmit" href="##" class="btn btn-primary">保 存</a>&nbsp;
             <a id="btnCancel" href="##" class="btn" onclick="history.go(-1)">返 回</a>

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

@@ -34,7 +34,7 @@
             <select class="input-small" id="status-select" name="status">
                 <option value="">不限</option>
                 <c:forEach items="${statusList}" var="item">
-                <option value="${item.value}" <c:if test="${query.status!=null && item.value==query.status.value}">selected</c:if>>${item.name}</option>
+                	 <option value="${item.value}" <c:if test="${item.value==status.value}">selected</c:if>>${item.name}</option>
                 </c:forEach>
             </select>
             <label>评卷员</label>

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

@@ -193,7 +193,7 @@
 					<a class="sheet-link" href="##" data-sheet-url="${student.sheetUrlString}" data-answer-url="<c:if test="${student.answerUrl!=null}">${cardServer}${student.answerUrl}</c:if>" data-title="${student.examNumber}&nbsp;&nbsp;${student.name}&nbsp;&nbsp;客观总分${student.objectiveScoreString}&nbsp;&nbsp;主观总分${student.subjectiveScoreString}&nbsp;&nbsp;全卷总分${student.totalScoreString}">原图</a>
 					<a class="track-link" href="##" data-image-url="${ctx}/admin/exam/track?studentId=${student.id}" data-title="${student.examNumber}&nbsp;&nbsp;${student.name}">阅卷轨迹</a>
 					<a class="package-link" href="##" data-image-url="${student.packageUrlString}" data-title="${student.packageCode}">签到表</a>
-					<a target="_blank" href="${ctx}/admin/mark/leader/index?studentId=${student.id}">给分</a>
+<%-- 					<a target="_blank" href="${ctx}/admin/mark/leader/index?studentId=${student.id}">给分</a> --%>
 				</td>
 			</tr>
 		</c:forEach>

+ 8 - 2
stmms-web/src/main/webapp/WEB-INF/views/modules/mark/markNew.jsp

@@ -34,6 +34,8 @@
 <script type="text/javascript" src="${ctxStatic}/mark-new/js/modules/change-name.js"></script>
 <script type="text/javascript" src="${ctxStatic}/mark-new/js/modules/tag-process.js"></script>
 <script type="text/javascript" src="${ctxStatic}/mark-new/js/modules/view-sidebar.js"></script>
+<script type="text/javascript" src="${ctxStatic}/mark-new/js/modules/specialTag.js"></script>
+
 </head>
 <body>
 	<div class="container-fluid" id="container"></div>
@@ -47,6 +49,7 @@
 				logoutUrl: '${ctx}/mark/logout',
 				clearUrl: '${ctx}/mark/clear',
 				switchTrackUrl: '${ctx}/mark/index?mode=track',
+				forceSpecialTag : '${forceSpecialTag}',
 				modules : {
 					'single-image-view' : {},
 					'image-builder': {},
@@ -60,7 +63,8 @@
 					'mark-board' : {
 						showScoreBoard : false,
 						autoSubmit : false,
-						needConfirm : false
+						needConfirm : false,
+              //        	showTotalScore:true
 					},
 					'sheet-view' : {
 						server : '${sheetServer}'
@@ -80,7 +84,9 @@
 							{title:'试卷',  url:'<c:if test="${subject.hasPaper==true}">${cardServer}${subject.paperUrl}</c:if>'},
 							{title:'答案',  url:'<c:if test="${subject.hasAnswer==true}">${cardServer}${subject.answerUrl}</c:if>'}
 						]
-					}
+					},
+                    'specialTag':{
+                    }
 				}
 			});
 			mc.start({

+ 43 - 2
stmms-web/src/main/webapp/static/mark-new/css/style.css

@@ -363,10 +363,22 @@ i,em {
 	font-weight: bold;
 	margin: 4px 0;
 }
-.mark-steps .step-board .newSubListCss{height: 20px;line-height: 19px; color: #333; display: block;text-align: center; font-family: "微软雅黑"; font-size: 16px; font-weight: normal; margin: 5px 0 5px 0;}
-.mark-steps .step-board .newSubListCss .red{ color: #ed5321; font-weight: bold; font-size: 16px; }
+.mark-steps .step-board .newSubListCss{height: 30px; line-height: 29px; color: #333; display: block;text-align: center; font-family: "微软雅黑"; font-size: 20px; font-weight: normal; margin: 5px 0 5px 0;}
+.mark-steps .step-board .newSubListCss .red{ color: #ed5321; font-weight: bold; font-size: 20px; }
 /*.sidebar .step-list .sublist .up{ height:27px; text-align:center; cursor:pointer;}
 .sidebar .step-list .sublist .down{height:22px; text-align:center; cursor:pointer;}*/
+
+.mark-steps  .picture-list{ height: 80px !important;overflow: auto; border-bottom: solid 1px #BBBBBB;}
+.mark-steps  .picture-list .pictureScore{ margin: 5px; overflow: hidden;}
+.mark-steps  .picture-list .pictureScore ul li{ float: left; height: 30px; width: 50px; border: solid 1px #cccccc; background-color: #FFFFFF; margin: 5px 5px;}
+.mark-steps  .picture-list .pictureScore ul li p{ font-size: 20px; line-height: 30px; color: #999999; text-align: center;}
+.mark-steps  .picture-list .pictureScore ul li a{display: block; font-size: 20px; line-height: 30px; color: #999999; text-align: center;}
+.mark-steps  .picture-list .pictureScore ul li a:hover{ background-color: #ED5321; color: #FFFFFF;}
+.mark-steps  .picture-list .pictureScore ul li.selected{ background-color: #ED5321; border: solid 1px #ED5321;}
+.mark-steps  .picture-list .pictureScore ul li.selected p{ color: #FFFFFF;}
+.mark-steps  .picture-list .pictureScore ul li.unable{ background-color: #dedede; border: solid 1px #dedede;}
+.mark-steps  .picture-list .pictureScore ul li.unable p{ color: #999999;}
+/*轨迹模式下提供“X”、“√”等标记符号   */
 .mark-steps .step-board .step-list .done {
 	width: 100%;
 	height: 118px;
@@ -1166,3 +1178,32 @@ a.button.all-zero-button {
 .username-input{
     margin-left: 12px;
 }
+.message-popover .popover-cont .username,.password,.password2 {
+    font-size: 12px;
+    color: #f00;
+    line-height: 30px;
+    padding-left: 20px;
+}
+.message-popover .popover-cont .username-input,.password-input,.password2-input{
+    width: 200px;
+}
+.message-popover .text-userInfo {
+    margin: 0px 0 15px 0;
+    width: 50px;
+    float: right;
+    margin-right: 20px;
+}
+
+.password-input,.password2-input{
+    margin-left: 20px;
+}
+
+.username-input{
+    margin-left: 12px;
+}
+.buttonCss .selected{
+    background-image: -webkit-linear-gradient(top, #eaeaea, #ED5321);
+}
+.buttonCss{
+    border-bottom: 1px solid #b50505;!important;
+}

+ 42 - 1
stmms-web/src/main/webapp/static/mark-new/js/mark-control.js

@@ -10,7 +10,8 @@ function MarkControl(option) {
         staticServer: option.staticServer,
         isFinish: false,
         prefetching: false,
-        prefetchTask: []
+        prefetchTask: [],
+        forceSpecialTag:option.forceSpecialTag
     };
     //初始化容器结构
     this.initContainer();
@@ -26,6 +27,7 @@ function MarkControl(option) {
 }
 
 MarkControl.prototype.initContainer = function() {
+
     var height = this.option.height;
     if (height == undefined) {
         height = $(window).height();
@@ -50,6 +52,9 @@ MarkControl.prototype.initContainer = function() {
     this.container.centerContent.css('height', height - this.container.header.parent().height());
 
     this.initHeaderAndAssistant();
+    
+	this.container.centerList = [];
+    this.navNumber = 0;
 }
 
 MarkControl.prototype.initHeaderAndAssistant = function() {
@@ -505,6 +510,17 @@ MarkControl.prototype.submitTask = function(submitUrl) {
         task.arbitrationList = undefined;
 
         this.trigger('task.submit.before');
+        this.trigger('mark.specialTag.before');
+        
+        //开启强制标记
+        if(markControl.context.forceSpecialTag){
+        	console.log(task);
+        	if(task.tagList==undefined ||task.tagList==null ||task.tagList.length <= 0){
+        		return ;
+        	}
+        }
+        
+        
         if (this.taskControl != undefined) {
             //已定义任务引擎
             this.taskControl.submit(task, function(status) {
@@ -514,6 +530,7 @@ MarkControl.prototype.submitTask = function(submitUrl) {
                 }
                 //markControl.context.task = undefined;
                 markControl.trigger('task.submit.success');
+                markControl.trigger('mark.specialTag.success');
                 //markControl.getTask();
             }, function(message) {
                 markControl.trigger('task.submit.error', message);
@@ -530,6 +547,7 @@ MarkControl.prototype.submitTask = function(submitUrl) {
                     if (result.success == true) {
                         //markControl.context.task = undefined;
                         markControl.trigger('task.submit.success');
+                        markControl.trigger('mark.specialTag.success');
                         //markControl.getTask();
                     } else {
                         markControl.trigger('task.submit.error', result.message);
@@ -541,10 +559,33 @@ MarkControl.prototype.submitTask = function(submitUrl) {
             });
         } else {
             markControl.trigger('task.submit.success');
+            markControl.trigger('mark.specialTag.success');
             //markControl.getTask();
         }
     }
 }
+MarkControl.prototype.addNavGroup = function(title, content){
+    var self = this;
+    self.navNumber++;
+    var nav = $('<a href="#"><span>'+title+'</span></a>').appendTo(self.container.centerNavbar);
+    nav.attr('data-number', self.navNumber);
+    content.attr('data-number', self.navNumber);
+    nav.click(function(){
+        self.container.centerNavbar.find('a').removeClass('selected');
+        $(this).addClass('selected');
+        
+        for(var i in self.container.centerList){
+        	var dom = self.container.centerList[i];
+        	if(dom.attr('data-number')==$(this).attr('data-number')){
+        		dom.show();
+        	}else{
+        		dom.hide();
+        	}
+        }
+    });
+    self.container.centerList.push(content);
+    return nav;
+}
 
 //默认要初始化的模块名称
 MarkControl.prototype.defaultModules = {

+ 2 - 0
stmms-web/src/main/webapp/static/mark-new/js/modules/mark-history.js

@@ -152,6 +152,8 @@ MarkHistory.prototype.onSearch = function(pageNumber) {
 }
 
 MarkHistory.prototype.onTaskSelect = function(index) {
+    //初始化--特殊标识
+    this.markControl.trigger('mark.specialTag.success');
     var number = new String(index);
     if (this.taskList != undefined && index < this.taskList.length && this.loading != true) {
         this.container.list.find('tr').each(function(index, obj) {

+ 250 - 0
stmms-web/src/main/webapp/static/mark-new/js/modules/simple-image-view.js

@@ -0,0 +1,250 @@
+//简单多张图片排列显示模块
+var single_image_view = function(option, success) {
+    var object = new SingleImageView(option);
+    success();
+    return object;
+}
+
+function SingleImageView(option) {
+    this.markControl = option.markControl;
+    this.defaultZoom = 100;
+    this.loading = false;
+    this.init();
+    this.markControl.on('step.board.show', this, function(event, context, eventObject) {
+        this.container.removeClass('span12');
+        this.container.addClass('span10');
+
+        this.container.perfectScrollbar('update');
+        if (this.iviewer != undefined) {
+            this.iviewer.iviewer('update');
+        }
+    });
+    this.markControl.on('step.board.hide', this, function(event, context, eventObject) {
+        this.container.removeClass('span10');
+        this.container.addClass('span12');
+
+        this.container.perfectScrollbar('update');
+        if (this.iviewer != undefined) {
+            this.iviewer.iviewer('update');
+        }
+    });
+    this.markControl.on('center.width.change', this, function(event, context, eventObject) {
+        this.container.perfectScrollbar('update');
+        if (this.iviewer != undefined) {
+            this.iviewer.iviewer('update');
+            this.iviewer.iviewer('fit');
+        }
+    });
+    this.markControl.on('view.sidebar.open', this, function(event, context, eventObject) {
+        this.imageControl.hide();
+    });
+    this.markControl.on('view.sidebar.close', this, function(event, context, eventObject) {
+        this.imageControl.show();
+    });
+    this.markControl.on('task.get.before', this, function(event, context, eventObject) {
+        this.task = undefined;
+        this.render();
+    });
+    this.markControl.on('task.get.success', this, function(event, context, eventObject) {
+        this.task = context.task;
+        this.render();
+    });
+    this.markControl.on('task.get.none', this, function(event, context, eventObject) {
+        this.task = undefined;
+        this.render();
+    });
+    this.markControl.on('image.position.change', this, function(event, context, topPercent) {
+        if (this.task != undefined && this.loading == false) {
+            this.updateScrollTop(topPercent);
+        }
+    });
+}
+
+SingleImageView.prototype.init = function() {
+    this.configCache = {};
+
+    //this.container = getDom(this.container_dom).appendTo(this.markControl.container.imageContent);
+    this.container = this.markControl.container.imageContent;
+    this.container.height(this.markControl.container.centerContent.height());
+    this.container.perfectScrollbar({
+        wheelSpeed: 20
+    });
+
+    this.imageHolder = getDom(this.image_holder_dom, this.markControl).appendTo(this.container);
+    this.imageHolder.width('100%');
+
+    this.imageControl = getDom(this.image_control_dom, this.markControl).insertBefore(this.markControl.container.assistantButton.parent());
+    this.imageControl.find('.zoom-out-button').click(this, function(event) {
+        var iviewer = event.data.iviewer;
+        if (iviewer != undefined) {
+            iviewer.iviewer('zoom_by', 1);
+        }
+    });
+    this.imageControl.find('.zoom-in-button').click(this, function(event) {
+        var iviewer = event.data.iviewer;
+        if (iviewer != undefined) {
+            iviewer.iviewer('zoom_by', -1);
+        }
+    });
+    this.imageControl.find('.zoom-fit-button').click(this, function(event) {
+        var iviewer = event.data.iviewer;
+        if (iviewer != undefined) {
+            iviewer.iviewer('fit');
+        }
+    });
+    this.imageControl.find('.zoom-origin-button').click(this, function(event) {
+        var iviewer = event.data.iviewer;
+        if (iviewer != undefined) {
+            iviewer.iviewer('set_zoom', 100);
+        }
+    });
+    this.imageControl.find('.rotate-button').click(this, function(event) {
+        var iviewer = event.data.iviewer;
+        if (iviewer != undefined) {
+            iviewer.iviewer('angle', 90);
+        }
+    });
+    var self = this;
+    this.container.scroll(function() {
+        if (self.currentConfig != undefined) {
+            self.currentConfig.scrollTop = self.container.scrollTop() / self.imageHolder.height();
+            self.currentConfig.scrollLeft = self.container.scrollLeft() / self.imageHolder.width();
+        }
+    });
+}
+
+SingleImageView.prototype.render = function() {
+    if (this.task != undefined) {
+        var config = this.configCache[this.task.blockId];
+        if (config == undefined) {
+            config = {
+                zoom: this.defaultZoom
+            };
+            this.configCache[this.task.blockId] = config;
+        }
+        this.currentConfig = config;
+
+        this.loadImage();
+        // this.imageControl.show();
+        // this.imageHolder.show();
+        // this.imageHolder.trigger('mouseenter');
+    } else {
+        this.imageControl.hide();
+        this.imageHolder.hide();
+        this.currentConfig = undefined;
+    }
+}
+
+SingleImageView.prototype.loadImage = function() {
+    if (this.task.imageData != undefined && this.loading == false) {
+        this.loading = true;
+        if (this.iviewer == undefined) {
+            var self = this;
+            this.iviewer = this.imageHolder.iviewer({
+                src: self.task.imageData,
+                zoom_delta: 1.2,
+                zoom: 100,
+                zoom_min: 10,
+                ui_disabled: true,
+                mousewheel: false,
+                zoom_animation: false,
+                onAfterZoom: function(ev, new_zoom) {
+                    self.onZoomSet(new_zoom);
+                },
+                onStopDrag: function(ev, point) {
+                    self.onStopDrag(point);
+                },
+                onFinishLoad: function(ev, url) {
+                    self.onImageLoad();
+                },
+                angle: function(ev, info) {
+                    self.onRotate(info.angle);
+                }
+            });
+            this.imageHolder.css('overflow', '');
+        } else {
+            this.iviewer.iviewer('loadImage', this.task.imageData);
+        }
+    }
+}
+
+SingleImageView.prototype.onImageLoad = function() {
+    this.loading = false;
+    this.container.scrollTop(0);
+    if (this.currentConfig != undefined && this.currentConfig.zoom != undefined && this.currentConfig.zoom != this.defaultZoom) {
+        if (this.currentConfig.rotate != undefined && this.currentConfig.rotate > 0) {
+            this.iviewer.iviewer('angle', this.currentConfig.rotate);
+        }
+        if (this.currentConfig.zoom != undefined && this.currentConfig.zoom != this.defaultZoom) {
+            this.iviewer.iviewer('set_zoom', this.currentConfig.zoom);
+        }
+
+    }
+    //this.imageHolder.find('img').css('border', '2px solid');
+
+    // if (this.currentConfig.dx != undefined && this.currentConfig.dy != undefined) {
+    //     this.iviewer.iviewer('moveTo', this.currentConfig.dx, this.currentConfig.dy);
+    // }
+    this.imageControl.show();
+    this.imageHolder.show();
+    this.imageHolder.trigger('mouseenter');
+
+    this.markControl.trigger('task.load.finish');
+}
+
+SingleImageView.prototype.onZoomSet = function(zoom) {
+    if (this.loading == false && this.currentConfig != undefined) {
+        this.currentConfig.zoom = zoom;
+        this.updateScrollTop(this.currentConfig.scrollTop);
+        this.updateScrollLeft(this.currentConfig.scrollLeft);
+    }
+}
+
+SingleImageView.prototype.onStopDrag = function(point) {
+    if (this.loading == false) {
+        this.currentConfig.dx = point.x;
+        this.currentConfig.dy = point.y;
+    }
+}
+
+SingleImageView.prototype.onRotate = function(angle) {
+    if (this.loading == false) {
+        this.currentConfig.rotate = angle;
+    }
+}
+
+SingleImageView.prototype.updateScrollTop = function(scrollTopPercent) {
+    var height = this.imageHolder.height();
+    var minHeight = this.container.height();
+    if (scrollTopPercent != undefined && scrollTopPercent >= 0 && scrollTopPercent <= 1 && height > minHeight) {
+        var left = height * (1 - scrollTopPercent);
+        var scrollTop = left > minHeight ? (height - left) : (height - minHeight);
+        this.container.scrollTop(scrollTop);
+    } else {
+        this.container.scrollTop(0);
+    }
+}
+
+SingleImageView.prototype.updateScrollLeft = function(scrollLeftPercent) {
+    var width = this.imageHolder.width();
+    var minWidth = this.container.width();
+    if (scrollLeftPercent != undefined && scrollLeftPercent >= 0 && scrollLeftPercent <= 1 && width > minWidth) {
+        var left = width * (1 - scrollLeftPercent);
+        var scrollLeft = left > minWidth ? (width - left) : (width - minWidth);
+        this.container.scrollLeft(scrollLeft);
+    } else {
+        this.container.scrollLeft(0);
+    }
+}
+
+SingleImageView.prototype.container_dom = '<div class="image-content"></div>';
+
+SingleImageView.prototype.image_control_dom = '<em>\
+<a href="#" class="btn zoom-out-button">放大</a>\
+<a href="#" class="btn zoom-in-button">缩小</a>\
+<a href="#" class="btn zoom-fit-button">适应</a>\
+<a href="#" class="btn zoom-origin-button">原始</a>\
+<a href="#" class="btn rotate-button">旋转</a>\
+</em>';
+
+SingleImageView.prototype.image_holder_dom = '<div style="position: relative;"></div>';

+ 69 - 201
stmms-web/src/main/webapp/static/mark-new/js/modules/single-image-view.js

@@ -7,244 +7,112 @@ var single_image_view = function(option, success) {
 
 function SingleImageView(option) {
     this.markControl = option.markControl;
-    this.defaultZoom = 100;
-    this.loading = false;
     this.init();
-    this.markControl.on('step.board.show', this, function(event, context, eventObject) {
-        this.container.removeClass('span12');
-        this.container.addClass('span10');
-
-        this.container.perfectScrollbar('update');
-        if (this.iviewer != undefined) {
-            this.iviewer.iviewer('update');
-        }
-    });
-    this.markControl.on('step.board.hide', this, function(event, context, eventObject) {
-        this.container.removeClass('span10');
-        this.container.addClass('span12');
-
-        this.container.perfectScrollbar('update');
-        if (this.iviewer != undefined) {
-            this.iviewer.iviewer('update');
-        }
-    });
     this.markControl.on('center.width.change', this, function(event, context, eventObject) {
-        this.container.perfectScrollbar('update');
-        if (this.iviewer != undefined) {
-            this.iviewer.iviewer('update');
-            this.iviewer.iviewer('fit');
-        }
-    });
-    this.markControl.on('view.sidebar.open', this, function(event, context, eventObject) {
-        this.imageControl.hide();
-    });
-    this.markControl.on('view.sidebar.close', this, function(event, context, eventObject) {
-        this.imageControl.show();
+        //this.container.perfectScrollbar('update');
     });
     this.markControl.on('task.get.before', this, function(event, context, eventObject) {
         this.task = undefined;
+        this.image = undefined;
         this.render();
     });
     this.markControl.on('task.get.success', this, function(event, context, eventObject) {
         this.task = context.task;
+        this.image = undefined;
         this.render();
     });
     this.markControl.on('task.get.none', this, function(event, context, eventObject) {
         this.task = undefined;
+        this.image = undefined;
         this.render();
     });
-    this.markControl.on('image.position.change', this, function(event, context, topPercent) {
-        if (this.task != undefined && this.loading == false) {
-            this.updateScrollTop(topPercent);
+    this.markControl.on('mark.track.show', this, function(event, context, track){
+        if(this.task != undefined && track != undefined){
+        	this.drawScore(track);
         }
     });
-}
-
-SingleImageView.prototype.init = function() {
-    this.configCache = {};
-
-    //this.container = getDom(this.container_dom).appendTo(this.markControl.container.imageContent);
-    this.container = this.markControl.container.imageContent;
-    this.container.height(this.markControl.container.centerContent.height());
-    this.container.perfectScrollbar({
-        wheelSpeed: 20
-    });
-
-    this.imageHolder = getDom(this.image_holder_dom, this.markControl).appendTo(this.container);
-    this.imageHolder.width('100%');
-
-    this.imageControl = getDom(this.image_control_dom, this.markControl).insertBefore(this.markControl.container.assistantButton.parent());
-    this.imageControl.find('.zoom-out-button').click(this, function(event) {
-        var iviewer = event.data.iviewer;
-        if (iviewer != undefined) {
-            iviewer.iviewer('zoom_by', 1);
-        }
-    });
-    this.imageControl.find('.zoom-in-button').click(this, function(event) {
-        var iviewer = event.data.iviewer;
-        if (iviewer != undefined) {
-            iviewer.iviewer('zoom_by', -1);
+    this.markControl.on('mark.specialTag.show', this, function(event, context, specialTag){
+        if(this.task != undefined && specialTag != undefined){
+        	this.drawTag(specialTag);
         }
     });
-    this.imageControl.find('.zoom-fit-button').click(this, function(event) {
-        var iviewer = event.data.iviewer;
-        if (iviewer != undefined) {
-            iviewer.iviewer('fit');
-        }
-    });
-    this.imageControl.find('.zoom-origin-button').click(this, function(event) {
-        var iviewer = event.data.iviewer;
-        if (iviewer != undefined) {
-            iviewer.iviewer('set_zoom', 100);
-        }
+    this.markControl.on('mark.track.clear', this, function(event, context, track){
+        this.reloadImage();
+        //显示特殊标记的历史痕迹
+        this.markControl.trigger('show.specialTag.event');
     });
-    this.imageControl.find('.rotate-button').click(this, function(event) {
-        var iviewer = event.data.iviewer;
-        if (iviewer != undefined) {
-            iviewer.iviewer('angle', 90);
-        }
+    this.markControl.on('mark.specialTag.clear', this, function(event, context, track){
+        this.reloadImage();
+        this.markControl.trigger('show.track.event');
     });
+}
+
+SingleImageView.prototype.init = function() {
     var self = this;
-    this.container.scroll(function() {
-        if (self.currentConfig != undefined) {
-            self.currentConfig.scrollTop = self.container.scrollTop() / self.imageHolder.height();
-            self.currentConfig.scrollLeft = self.container.scrollLeft() / self.imageHolder.width();
+    this.container = getDom(this.container_dom, this.markControl).appendTo(this.markControl.container.centerContent);
+    this.container.height(this.markControl.container.centerContent.height());
+    //this.container.perfectScrollbar({
+    //    wheelSpeed: 20
+    //});
+    this.markControl.addNavGroup('答卷', this.container);
+    
+    this.canvas = this.container.find('canvas')[0];
+    this.ctx = this.canvas.getContext("2d");
+    
+    $(this.canvas).click(function(event){
+        if(self.task != undefined){
+        	self.markControl.trigger('mark.track.set', {
+        		positionX: ((event.pageX - $(self.canvas).offset().left)/$(self.canvas).width()).toFixed(3),
+                positionY: ((event.pageY - $(self.canvas).offset().top)/$(self.canvas).height()).toFixed(3)
+        	});
+
+        	self.markControl.trigger('mark.specialTag.set', {
+        		positionX: ((event.pageX - $(self.canvas).offset().left)/$(self.canvas).width()).toFixed(3),
+                positionY: ((event.pageY - $(self.canvas).offset().top)/$(self.canvas).height()).toFixed(3)
+        	});
         }
     });
 }
 
 SingleImageView.prototype.render = function() {
-    if (this.task != undefined) {
-        var config = this.configCache[this.task.blockId];
-        if (config == undefined) {
-            config = {
-                zoom: this.defaultZoom
-            };
-            this.configCache[this.task.blockId] = config;
-        }
-        this.currentConfig = config;
-
-        this.loadImage();
-        // this.imageControl.show();
-        // this.imageHolder.show();
-        // this.imageHolder.trigger('mouseenter');
-    } else {
-        this.imageControl.hide();
-        this.imageHolder.hide();
-        this.currentConfig = undefined;
-    }
-}
-
-SingleImageView.prototype.loadImage = function() {
-    if (this.task.imageData != undefined && this.loading == false) {
-        this.loading = true;
-        if (this.iviewer == undefined) {
-            var self = this;
-            this.iviewer = this.imageHolder.iviewer({
-                src: self.task.imageData,
-                zoom_delta: 1.2,
-                zoom: 100,
-                zoom_min: 10,
-                ui_disabled: true,
-                mousewheel: false,
-                zoom_animation: false,
-                onAfterZoom: function(ev, new_zoom) {
-                    self.onZoomSet(new_zoom);
-                },
-                onStopDrag: function(ev, point) {
-                    self.onStopDrag(point);
-                },
-                onFinishLoad: function(ev, url) {
-                    self.onImageLoad();
-                },
-                angle: function(ev, info) {
-                    self.onRotate(info.angle);
-                }
-            });
-            this.imageHolder.css('overflow', '');
-        } else {
-            this.iviewer.iviewer('loadImage', this.task.imageData);
-        }
-    }
-}
-
-SingleImageView.prototype.onImageLoad = function() {
-    this.loading = false;
-    this.container.scrollTop(0);
-    if (this.currentConfig != undefined && this.currentConfig.zoom != undefined && this.currentConfig.zoom != this.defaultZoom) {
-        if (this.currentConfig.rotate != undefined && this.currentConfig.rotate > 0) {
-            this.iviewer.iviewer('angle', this.currentConfig.rotate);
-        }
-        if (this.currentConfig.zoom != undefined && this.currentConfig.zoom != this.defaultZoom) {
-            this.iviewer.iviewer('set_zoom', this.currentConfig.zoom);
+    var self = this;
+    $(this.canvas).hide();
+    if (this.task != undefined && this.task.imageData != undefined) {
+        //设置画布大小及背景颜色
+        this.image = new Image();
+        this.image.src = this.task.imageData;
+        this.image.onload = function(){
+            self.canvas.width = Math.min(self.container.width(), self.image.width);
+            self.canvas.height = self.canvas.width * self.image.height / self.image.width;
+            self.ctx.fillStyle = "#FFFFFF";
+            self.ctx.drawImage(self.image, 0, 0, self.image.width, self.image.height, 0, 0, self.canvas.width, self.canvas.height);
+            $(self.canvas).show();
+            
+            self.markControl.trigger('task.load.finish');
         }
-
-    }
-    //this.imageHolder.find('img').css('border', '2px solid');
-
-    // if (this.currentConfig.dx != undefined && this.currentConfig.dy != undefined) {
-    //     this.iviewer.iviewer('moveTo', this.currentConfig.dx, this.currentConfig.dy);
-    // }
-    this.imageControl.show();
-    this.imageHolder.show();
-    this.imageHolder.trigger('mouseenter');
-
-    this.markControl.trigger('task.load.finish');
-}
-
-SingleImageView.prototype.onZoomSet = function(zoom) {
-    if (this.loading == false && this.currentConfig != undefined) {
-        this.currentConfig.zoom = zoom;
-        this.updateScrollTop(this.currentConfig.scrollTop);
-        this.updateScrollLeft(this.currentConfig.scrollLeft);
-    }
-}
-
-SingleImageView.prototype.onStopDrag = function(point) {
-    if (this.loading == false) {
-        this.currentConfig.dx = point.x;
-        this.currentConfig.dy = point.y;
     }
 }
 
-SingleImageView.prototype.onRotate = function(angle) {
-    if (this.loading == false) {
-        this.currentConfig.rotate = angle;
+SingleImageView.prototype.reloadImage = function() {
+    if(this.image != undefined){
+        this.ctx.drawImage(this.image, 0, 0, this.image.width, this.image.height, 0, 0, this.canvas.width, this.canvas.height);
     }
 }
 
-SingleImageView.prototype.updateScrollTop = function(scrollTopPercent) {
-    var height = this.imageHolder.height();
-    var minHeight = this.container.height();
-    if (scrollTopPercent != undefined && scrollTopPercent >= 0 && scrollTopPercent <= 1 && height > minHeight) {
-        var left = height * (1 - scrollTopPercent);
-        var scrollTop = left > minHeight ? (height - left) : (height - minHeight);
-        this.container.scrollTop(scrollTop);
-    } else {
-        this.container.scrollTop(0);
+SingleImageView.prototype.drawScore = function(track){
+    if(track != undefined && track.positionX > 0 && track.positionY > 0){
+        this.ctx.font ="60px Arial";
+        this.ctx.fillStyle = 'red';
+        this.ctx.fillText(track.score, track.positionX*this.canvas.width, track.positionY*this.canvas.height);
     }
 }
 
-SingleImageView.prototype.updateScrollLeft = function(scrollLeftPercent) {
-    var width = this.imageHolder.width();
-    var minWidth = this.container.width();
-    if (scrollLeftPercent != undefined && scrollLeftPercent >= 0 && scrollLeftPercent <= 1 && width > minWidth) {
-        var left = width * (1 - scrollLeftPercent);
-        var scrollLeft = left > minWidth ? (width - left) : (width - minWidth);
-        this.container.scrollLeft(scrollLeft);
-    } else {
-        this.container.scrollLeft(0);
+SingleImageView.prototype.drawTag = function(specialTag){
+    if(specialTag != undefined && specialTag.positionX > 0 && specialTag.positionY > 0){
+        this.ctx.font ="60px Arial";
+        this.ctx.fillStyle = 'red';
+        this.ctx.fillText(specialTag.tagName, specialTag.positionX*this.canvas.width, specialTag.positionY*this.canvas.height);
     }
 }
 
-SingleImageView.prototype.container_dom = '<div class="image-content"></div>';
-
-SingleImageView.prototype.image_control_dom = '<em>\
-<a href="#" class="btn zoom-out-button">放大</a>\
-<a href="#" class="btn zoom-in-button">缩小</a>\
-<a href="#" class="btn zoom-fit-button">适应</a>\
-<a href="#" class="btn zoom-origin-button">原始</a>\
-<a href="#" class="btn rotate-button">旋转</a>\
-</em>';
-
-SingleImageView.prototype.image_holder_dom = '<div style="position: relative;"></div>';
+SingleImageView.prototype.container_dom = '<div style="overflow: scroll; width: 100%"><canvas></canvas></div>';

+ 164 - 0
stmms-web/src/main/webapp/static/mark-new/js/modules/specialTag.js

@@ -0,0 +1,164 @@
+//特殊标识模块
+var specialTag = function(option, success) {
+    var object = new SpecialTag(option);
+    success();
+    return object;
+}
+
+function SpecialTag(option) {
+    this.markControl = option.markControl;
+    this.maxWidth = option.width != undefined ? option.width : 200;
+    this.show = false;
+    this.tagList = [];
+    this.specialTag = undefined;
+    this.init();
+    this.markControl.on('mark.specialTag.set', this, function(event, context, specialTag) {
+        if(this.specialTag != undefined && this.tagList != undefined){
+            specialTag.tagName = this.specialTag;
+            this.tagList.push(specialTag);
+            this.markControl.trigger('mark.specialTag.show', specialTag);
+        }
+    })
+    //提交保存之前
+    this.markControl.on('mark.specialTag.before', this, function(event, context, eventObject) {
+        this.task = context.task;
+        if (this.tagList.length > 0) {
+            this.task.tagList = this.tagList;
+        } else {
+            this.task.tagList = undefined;
+        }
+    });
+    //提交保存成功后
+    this.markControl.on('mark.specialTag.success', this, function(event, context, eventObject) {
+        this.markControl.trigger('clear.specialTag.click');
+        this.specialTag = undefined;
+        this.tagList = [];
+    });
+
+    //禁止 特殊标识使用
+    this.markControl.on('click.track.before', this, function(event, context, eventObject) {
+        this.specialTag = undefined;
+        this.markControl.trigger('clear.specialTag.click');
+    });
+
+    //显示痕迹
+    this.markControl.on('show.specialTag.event', this, function(event, context, eventObject) {
+        this.task = context.task;
+        if(this.task != undefined ){
+            if(this.tagList.length == 0 && this.task.tagList != null && this.task.tagList.length>0){
+                this.tagList = this.task.tagList;
+            }
+            for(var j = 0; j <this.tagList.length; j++) {
+                this.markControl.trigger('mark.specialTag.show', this.tagList[j]);
+            }
+        }
+    });
+
+    //清除按钮选中
+    this.markControl.on('clear.specialTag.click', this, function(event, context, eventObject) {
+        this.specialTag = undefined;
+        var aList = this.onclickList.find('a');
+        for(var i =0 ;i < aList.length;i++){
+                $(aList[i]).removeClass('selected');
+        }
+    })
+}
+
+SpecialTag.prototype.init = function() {
+    var self = this;
+    this.container = getDom(this.container_dom, this.markControl).appendTo(this.markControl.container);
+    this.container.width(this.maxWidth);
+    this.container.offset({
+        top: 100,
+        left:800
+    });
+    this.container.header = getDom(this.container_header_dom, this.markControl).appendTo(this.container);
+    this.container.header.width('100%');
+
+    this.container.content = getDom(this.container_content_dom, this.markControl).appendTo(this.container);
+    this.container.content.width('100%');
+
+    this.onclickList = this.container.content.find('#problem-list');
+
+    this.clearList = this.container.content.find('#clear');
+
+    this.container.draggable({
+        containment: "window"
+    });
+
+    this.onclickList.find('a').click(function () {
+        self.specialTag = undefined;
+        self.markControl.trigger('click.specialTag.before');
+        if($(this).hasClass('selected')){
+            $(this).removeClass('selected');
+        }else {
+            self.specialTag = $(this).attr('value');
+            $(this).addClass('selected');
+            var aList = self.onclickList.find('a');
+            for(var i =0 ;i < aList.length;i++){
+                if($(aList[i]).attr('value') != $(this).attr('value')){
+                    $(aList[i]).removeClass('selected');
+                }
+            }
+        }
+    });
+
+    this.clearList.find('a').click(function () {
+        self.markControl.trigger('clear.specialTag.click');
+        self.markControl.trigger('click.specialTag.before');
+        if(self.tagList != undefined && self.tagList.length>0){
+            self.markControl.trigger('mark.specialTag.clear');
+            if($(this).attr('class') == 'goBack'){
+                    self.tagList.pop();
+                    self.markControl.trigger('show.specialTag.event');
+                }else if($(this).attr('class') == 'clearAll'){
+                    self.tagList = [];
+                    self.task.tagList = [];
+            }
+        }
+    });
+
+    this.container.header.find('#close-button').click(function() {
+        self.toggle(false);
+    });
+
+    this.control = getDom(this.control_dom, this.markControl).appendTo(this.markControl.container.assistant);
+    this.control.find('#show-SpecialTag-button').click(function() {
+        self.markControl.container.assistant.hide();
+        self.toggle(true);
+    });
+    this.control.find('#hide-SpecialTag-button').click(function() {
+        self.markControl.container.assistant.hide();
+        self.toggle(false);
+    });
+}
+
+SpecialTag.prototype.toggle = function(show) {
+    this.specialTag = undefined;
+    if (show == true) {
+        this.show = true;
+        this.container.show();
+    } else {
+        this.show = false;
+        this.container.hide();
+    }
+}
+
+SpecialTag.prototype.container_dom = '<div class="score-board score-board-popover" style="display:none"></div>';
+
+SpecialTag.prototype.container_header_dom = '<div class="header" style="border-radius: 15px 15px 0px 0px;">\
+<p class="fl" id="header">特殊标记</p>\
+<a class="header-close" id="close-button" href="#"><img src="{staticServer}/images/close.png"></a>\
+</div>';
+
+SpecialTag.prototype.container_content_dom = '<div class="content popover-content" style="padding:4px;border-radius: 0px 0px 15px 15px;">\
+<p id="problem-list" class="popover-list buttonCss">\
+    <a href="#" value="√">√</a>\
+    <a href="#" value="X">×</a>\
+    <a href="#" value="乄">乄</a>\
+    </p><p id="clear"><a href="#" class="goBack" style="margin-left: 20px;">回&nbsp;&nbsp;&nbsp;退</a><a href="#" class="clearAll">全部清除</a></p></div>';
+
+SpecialTag.prototype.control_dom = '<h3 class="popover-title">特殊标记</h3>\
+<div class="popover-content"><p id="problem-list" class="popover-list">\
+<a href="#" id="show-SpecialTag-button">打开</a><a href="#" id="hide-SpecialTag-button">关闭</a>\
+</p></div>';