Преглед изворни кода

考生图片部分功能扩展

1.增加带轨迹原图转存功能
2.成绩查询增加带轨迹的裁切图全部展示功能
3.标记试卷功能按大题查评卷任务,并增加打回功能,类似评卷任务管理
luoshi пре 6 година
родитељ
комит
0dfdfd7d2f

+ 5 - 1
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/ExamStudentService.java

@@ -6,7 +6,9 @@ import java.util.Map;
 
 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.query.ExamStudentSearchQuery;
+import cn.com.qmth.stmms.biz.utils.OriginTag;
 import cn.com.qmth.stmms.biz.utils.PictureTag;
 
 public interface ExamStudentService {
@@ -110,6 +112,8 @@ public interface ExamStudentService {
     List<Object[]> statisticsByAbsentAndBreach(Integer examId, String code, Boolean upload, boolean absent,
             boolean breach);
 
-	Map<Integer, List<PictureTag>> buildSheetTags(ExamStudent student);
+    Map<Integer, List<PictureTag>> buildSheetTags(ExamStudent student);
+
+    Map<MarkGroup, List<OriginTag>> getSliceTags(ExamStudent student);
 
 }

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

@@ -723,58 +723,79 @@ public class ExamStudentServiceImpl extends BaseQueryService<ExamStudent> implem
         List<PictureConfigItem> sliceConfig = PictureConfigItem.parse(exam.getSliceConfig());
         if (!sliceConfig.isEmpty()) {
             // 裁切图配置存在时才继续下面内容
-            DecimalFormat format = new DecimalFormat("###.#");
             List<ExamQuestion> questions = questionService.findByExamAndSubjectAndObjective(student.getExamId(),
                     student.getSubjectCode(), false);
             List<ScoreItem> scoreList = student.getScoreList(false);
             List<MarkGroup> markGroups = groupService.findByExamAndSubject(student.getExamId(),
                     student.getSubjectCode());
             for (MarkGroup group : markGroups) {
-                // 从考生主观题得分中拆解出本大题得分
-                double score = 0;
-                List<Double> details = new ArrayList<>();
-                int i = -1;
-                for (ExamQuestion question : questions) {
-                    i++;
-                    if (question.getMainNumber().equals(group.getNumber())) {
-                        double value = scoreList.size() > i ? scoreList.get(i).getScore() : 0;
-                        score += value;
-                        details.add(value);
-                    }
-                }
-                // 原图中需要显示的内容列表
-                List<OriginTag> originTags = new LinkedList<>();
-                // 首先添加本大题总得分
-                originTags.add(new OriginTag(format.format(score), 0.1, 0.01));
-                // 检测应该使用哪个评卷任务的轨迹记录
-                MarkLibrary selected = null;
-                List<MarkLibrary> libraries = libraryService.findByStudentAndGroup(student.getId(), group.getNumber());
-                for (MarkLibrary library : libraries) {
-                    if (checkScore(library, score, details)) {
-                        selected = library;
-                        break;
-                    }
-                }
-                if (selected != null) {
-                    // 添加轨迹分
-                    List<MarkTrack> tracks = trackService.findByLibraryId(selected.getId());
-                    for (MarkTrack markTrack : tracks) {
-                        originTags.add(new OriginTag(format.format(markTrack.getScore()), markTrack.getPositionX(),
-                                markTrack.getPositionY()));
-                    }
-                    // 添加特殊标记
-                    List<MarkSpecialTag> specialTags = specialTagService.findByLibraryId(selected.getId());
-                    for (MarkSpecialTag markSpecialTag : specialTags) {
-                        originTags.add(new OriginTag(markSpecialTag.getTagName(), markSpecialTag.getPositionX(),
-                                markSpecialTag.getPositionY()));
-                    }
-                }
-                tagMap.put(group, originTags);
+                tagMap.put(group, buildOriginTags(student, group, questions, scoreList));
             }
         }
         return PictureConfigTransform.process(sliceConfig, tagMap);
     }
 
+    /**
+     * 根据考生获取所有评卷分组的标记内容
+     */
+    @Override
+    public Map<MarkGroup, List<OriginTag>> getSliceTags(ExamStudent student) {
+        Map<MarkGroup, List<OriginTag>> tagMap = new HashMap<MarkGroup, List<OriginTag>>();
+        List<ExamQuestion> questions = questionService.findByExamAndSubjectAndObjective(student.getExamId(),
+                student.getSubjectCode(), false);
+        List<ScoreItem> scoreList = student.getScoreList(false);
+        List<MarkGroup> markGroups = groupService.findByExamAndSubject(student.getExamId(), student.getSubjectCode());
+        for (MarkGroup group : markGroups) {
+            tagMap.put(group, buildOriginTags(student, group, questions, scoreList));
+        }
+        return tagMap;
+    }
+
+    private List<OriginTag> buildOriginTags(ExamStudent student, MarkGroup group, List<ExamQuestion> questions,
+            List<ScoreItem> scoreList) {
+        DecimalFormat format = new DecimalFormat("###.#");
+        // 从考生主观题得分中拆解出本大题得分
+        double score = 0;
+        List<Double> details = new ArrayList<>();
+        int i = -1;
+        for (ExamQuestion question : questions) {
+            i++;
+            if (question.getMainNumber().equals(group.getNumber())) {
+                double value = scoreList.size() > i ? scoreList.get(i).getScore() : 0;
+                score += value;
+                details.add(value);
+            }
+        }
+        // 原图中需要显示的内容列表
+        List<OriginTag> originTags = new LinkedList<>();
+        // 首先添加本大题总得分
+        originTags.add(new OriginTag(format.format(score), 0.1, 0.01));
+        // 检测应该使用哪个评卷任务的轨迹记录
+        MarkLibrary selected = null;
+        List<MarkLibrary> libraries = libraryService.findByStudentAndGroup(student.getId(), group.getNumber());
+        for (MarkLibrary library : libraries) {
+            if (checkScore(library, score, details)) {
+                selected = library;
+                break;
+            }
+        }
+        if (selected != null) {
+            // 添加轨迹分
+            List<MarkTrack> tracks = trackService.findByLibraryId(selected.getId());
+            for (MarkTrack markTrack : tracks) {
+                originTags.add(new OriginTag(format.format(markTrack.getScore()), markTrack.getPositionX(),
+                        markTrack.getPositionY()));
+            }
+            // 添加特殊标记
+            List<MarkSpecialTag> specialTags = specialTagService.findByLibraryId(selected.getId());
+            for (MarkSpecialTag markSpecialTag : specialTags) {
+                originTags.add(new OriginTag(markSpecialTag.getTagName(), markSpecialTag.getPositionX(),
+                        markSpecialTag.getPositionY()));
+            }
+        }
+        return originTags;
+    }
+
     private boolean checkScore(MarkLibrary library, double score, List<Double> details) {
         if (library.getMarkerScore() == null) {
             return false;

+ 13 - 13
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/utils/OriginTag.java

@@ -4,18 +4,18 @@ public class OriginTag {
 
     private String content;
 
-    private double poxitionX;
+    private double positionX;
 
-    private double poxitionY;
+    private double positionY;
 
     public OriginTag() {
 
     }
 
-    public OriginTag(String content, double poxitionX, double poxitionY) {
+    public OriginTag(String content, double positionX, double positionY) {
         this.content = content;
-        this.poxitionX = poxitionX;
-        this.poxitionY = poxitionY;
+        this.positionX = positionX;
+        this.positionY = positionY;
     }
 
     public String getContent() {
@@ -26,20 +26,20 @@ public class OriginTag {
         this.content = content;
     }
 
-    public double getPoxitionX() {
-        return poxitionX;
+    public double getPositionX() {
+        return positionX;
     }
 
-    public void setPoxitionX(double poxitionX) {
-        this.poxitionX = poxitionX;
+    public void setPositionX(double positionX) {
+        this.positionX = positionX;
     }
 
-    public double getPoxitionY() {
-        return poxitionY;
+    public double getPositionY() {
+        return positionY;
     }
 
-    public void setPoxitionY(double poxitionY) {
-        this.poxitionY = poxitionY;
+    public void setPositionY(double positionY) {
+        this.positionY = positionY;
     }
 
 }

+ 2 - 2
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/utils/PictureConfigTransform.java

@@ -63,8 +63,8 @@ public class PictureConfigTransform {
             // 遍历所有显示元素
             for (OriginTag tag : tags) {
                 // 计算显示元素在拼接图内的绝对位置
-                int left = (int) (maxWidth * tag.getPoxitionX());
-                int top = (int) (totalHeight * tag.getPoxitionY());
+                int left = (int) (maxWidth * tag.getPositionX());
+                int top = (int) (totalHeight * tag.getPositionY());
                 int start = 0;
                 for (PictureConfigItem config : groupConfigs) {
                     if (config.getW() > 0 && config.getH() > 0) {

+ 5 - 0
stmms-common/src/main/java/cn/com/qmth/stmms/common/utils/PictureUrlBuilder.java

@@ -45,6 +45,11 @@ public class PictureUrlBuilder {
                 examNumber, String.valueOf(index), DEFAULT_SUFFIX);
     }
 
+    public static String getSliceUrl(int examId, int campusId, String subjectCode, String examNumber, int index) {
+        return MessageFormat.format(SLICE_URL_TEMPLATE, String.valueOf(examId), String.valueOf(campusId), subjectCode,
+                examNumber, String.valueOf(index), DEFAULT_SUFFIX);
+    }
+
     public static List<String> getSliceUrls(int examId, int campusId, String subjectCode, String examNumber,
             int count) {
         List<String> list = new LinkedList<String>();

+ 33 - 0
stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/MarkTrackController.java

@@ -3,14 +3,19 @@ package cn.com.qmth.stmms.admin.exam;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
 
+import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.servlet.ModelAndView;
 
 import cn.com.qmth.stmms.biz.campus.model.Campus;
 import cn.com.qmth.stmms.biz.campus.service.CampusService;
@@ -24,7 +29,10 @@ import cn.com.qmth.stmms.biz.mark.model.MarkTrack;
 import cn.com.qmth.stmms.biz.mark.service.MarkLibraryService;
 import cn.com.qmth.stmms.biz.mark.service.MarkSpecialTagService;
 import cn.com.qmth.stmms.biz.mark.service.MarkTrackService;
+import cn.com.qmth.stmms.biz.utils.OriginTag;
 import cn.com.qmth.stmms.common.utils.PictureUrlBuilder;
+import net.sf.json.JSONArray;
+import net.sf.json.JSONObject;
 
 @Controller("trackController")
 @RequestMapping("/admin/exam/track")
@@ -53,6 +61,31 @@ public class MarkTrackController extends BaseExamController {
     @Autowired
     private MarkSpecialTagService markSpecialTagService;
 
+    @RequestMapping("/student/{studentId}")
+    public ModelAndView view(@PathVariable Integer studentId) {
+        ModelAndView view = new ModelAndView("modules/exam/studentTrack");
+        view.addObject("imageServer", imageServer);
+        ExamStudent student = studentService.findById(studentId);
+        if (student != null && student.isUpload()) {
+            Campus campus = campusService.findBySchoolAndName(student.getSchoolId(), student.getCampusName());
+            List<String> sliceUrls = PictureUrlBuilder.getSliceUrls(student.getExamId(), campus.getId(),
+                    student.getSubjectCode(), student.getExamNumber(), student.getSliceCount());
+            view.addObject("urls", StringUtils.join(sliceUrls, ","));
+
+            JSONArray result = new JSONArray();
+            Map<MarkGroup, List<OriginTag>> maps = studentService.getSliceTags(student);
+            for (Entry<MarkGroup, List<OriginTag>> entry : maps.entrySet()) {
+                MarkGroup group = entry.getKey();
+                JSONObject item = new JSONObject();
+                item.accumulate("config", group.getPictureConfigList());
+                item.accumulate("tags", entry.getValue());
+                result.add(item);
+            }
+            view.addObject("tags", result.toString());
+        }
+        return view;
+    }
+
     /**
      * 
      * @param request

+ 8 - 12
stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/TagController.java

@@ -15,15 +15,13 @@ import org.springframework.web.bind.annotation.RequestMapping;
 
 import cn.com.qmth.stmms.biz.campus.model.Campus;
 import cn.com.qmth.stmms.biz.campus.service.CampusService;
-import cn.com.qmth.stmms.biz.exam.model.ExamStudent;
 import cn.com.qmth.stmms.biz.exam.service.ExamStudentService;
+import cn.com.qmth.stmms.biz.exam.service.MarkerService;
 import cn.com.qmth.stmms.biz.exam.service.TagService;
 import cn.com.qmth.stmms.biz.mark.model.MarkLibrary;
 import cn.com.qmth.stmms.biz.mark.query.MarkLibrarySearchQuery;
 import cn.com.qmth.stmms.biz.mark.service.MarkLibraryService;
 import cn.com.qmth.stmms.common.domain.WebUser;
-import cn.com.qmth.stmms.common.utils.DateUtils;
-import cn.com.qmth.stmms.common.utils.PictureUrlBuilder;
 import cn.com.qmth.stmms.common.utils.RequestUtils;
 
 @Controller("tagController")
@@ -41,6 +39,9 @@ public class TagController extends BaseExamController {
     @Autowired
     private MarkLibraryService libraryService;
 
+    @Autowired
+    private MarkerService markerService;
+
     @Autowired
     private TagService tagService;
 
@@ -67,17 +68,12 @@ public class TagController extends BaseExamController {
         }
         subjectFilter(query, wu);
         query = libraryService.findByQuery(query);
-
-        List<ExamStudent> list = new LinkedList<ExamStudent>();
         for (MarkLibrary library : query.getResult()) {
-            ExamStudent student = studentService.findById(library.getStudentId());
-            student.setSheetUrls(PictureUrlBuilder.getSheetUrls(examId, library.getCampusId(), student.getSubjectCode(),
-                    student.getExamNumber(), student.getSheetCount()));
-            student.setMarkTime(DateUtils.formatDateTime(library.getMarkerTime()));
-            student.setLibraryId(library.getId());
-            list.add(student);
+            if (library.getMarkerId() != null) {
+                library.setMarker(markerService.findById(library.getMarkerId()));
+            }
         }
-        model.addAttribute("resultList", list);
+
         model.addAttribute("query", query);
         model.addAttribute("subjectList", getTagSubject(examId, wu));
         model.addAttribute("campusList", getTagCampus(examId));

+ 30 - 5
stmms-web/src/main/java/cn/com/qmth/stmms/api/controller/PictureController.java

@@ -70,6 +70,9 @@ public class PictureController {
     @Value("${file.root}")
     private String baseDir;
 
+    @Value("${file.save}")
+    private String saveDir;
+
     @RequestMapping("/sheet/{examId}/{examNumber}-{index}")
     public void getSheet(HttpServletResponse response, @PathVariable Integer examId, @PathVariable String examNumber,
             @PathVariable Integer index, @RequestParam(required = false, defaultValue = "true") Boolean withTag)
@@ -106,15 +109,23 @@ public class PictureController {
             result.accumulate("message", "exam not exists");
             return result;
         }
-        if (StringUtils.isBlank(baseDir)) {
+        if (StringUtils.isBlank(saveDir)) {
             result.accumulate("success", false);
-            result.accumulate("message", "file.root not exists");
+            result.accumulate("message", "file.save not exists");
             return result;
         }
         if (lockService.trylock(LockType.EXAM, examId)) {
-            taskExecutor.submit(new SheetDownloadThread(examId, baseDir, this, studentService, lockService));
+            taskExecutor.submit(new SheetDownloadThread(examId, saveDir, this, studentService, lockService));
         }
-        result.accumulate("running", true);
+        result.accumulate("running", lockService.isLocked(LockType.EXAM, examId));
+        return result;
+    }
+
+    @RequestMapping("/sheets/{examId}/status")
+    @ResponseBody
+    public Object getAllSheet(HttpServletResponse response, @PathVariable Integer examId) throws IOException {
+        JSONObject result = new JSONObject();
+        result.accumulate("running", lockService.isLocked(LockType.EXAM, examId));
         return result;
     }
 
@@ -123,7 +134,7 @@ public class PictureController {
         String url = PictureUrlBuilder.getSheetUrl(student.getExamId(), campus.getId(), student.getSubjectCode(),
                 student.getExamNumber(), index);
         if (StringUtils.isNotBlank(baseDir)) {
-            return ImageIO.read(new File(baseDir, url));
+            return ImageIO.read(new File(new File(baseDir, config.getSheetBucket()), url));
         } else {
             UpYun upyun = new UpYun(config.getSheetBucket(), config.getSheetUsername(), config.getSheetPassword());
             ByteArrayOutputStream ous = new ByteArrayOutputStream();
@@ -132,4 +143,18 @@ public class PictureController {
         }
     }
 
+    public BufferedImage getSliceImage(ExamStudent student, int index) throws FileNotFoundException, IOException {
+        Campus campus = campusService.findBySchoolAndName(student.getSchoolId(), student.getCampusName());
+        String url = PictureUrlBuilder.getSliceUrl(student.getExamId(), campus.getId(), student.getSubjectCode(),
+                student.getExamNumber(), index);
+        if (StringUtils.isNotBlank(baseDir)) {
+            return ImageIO.read(new File(new File(baseDir, config.getSliceBucket()), url));
+        } else {
+            UpYun upyun = new UpYun(config.getSliceBucket(), config.getSliceUsername(), config.getSlicePassword());
+            ByteArrayOutputStream ous = new ByteArrayOutputStream();
+            upyun.readFile(url, ous);
+            return ImageIO.read(new ByteArrayInputStream(ous.toByteArray()));
+        }
+    }
+
 }

+ 2 - 0
stmms-web/src/main/java/cn/com/qmth/stmms/api/utils/SheetDownloadThread.java

@@ -56,6 +56,7 @@ public class SheetDownloadThread implements Runnable {
             }
 
             for (ExamStudent student : query.getResult()) {
+                log.warn("write for student: " + student.getExamNumber());
                 for (int i = 1; i <= student.getSheetCount(); i++) {
                     download(student, i);
                 }
@@ -73,6 +74,7 @@ public class SheetDownloadThread implements Runnable {
             BufferedImage image = SheetBuildUtil.buildSheetImage(controller.getSheetImage(student, index),
                     studentService.buildSheetTags(student).get(index));
             ImageIO.write(image, "jpg", file);
+            log.warn("write sheet file success: " + file.getAbsolutePath());
         } catch (Exception e) {
             log.error("write sheet file error: " + file.getAbsolutePath(), e);
         }

+ 1 - 0
stmms-web/src/main/webapp/WEB-INF/application.properties

@@ -26,6 +26,7 @@ card.server=http://ft-card.markingcloud.com
 
 ##file root path
 file.root=
+file.save=/Users/luoshi/develop/data/stmms-ft
 
 ##upyun image config
 upyun.sheet.bucket=ft-sheet

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

@@ -165,6 +165,7 @@
 				<td>
 				    <c:if test="${student.upload==true}">
 					<a class="sheet-link" href="##" data-id="${student.id}" 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 href="${ctx}/admin/exam/track/student/${student.id}" target="_blank">轨迹图</a>
 					</c:if>
 					<c:if test="${student.packageUrlString!=null && student.packageUrlString!=''}">
 					<a class="package-link" href="##" data-image-url="${student.packageUrlString}" data-title="${student.packageCode}">签到表</a>

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

@@ -0,0 +1,112 @@
+<%@ page language="java" pageEncoding="utf-8"%>
+<%@ include file="/WEB-INF/views/include/taglib.jsp"%>
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<title>云阅卷</title>
+<meta name="viewport" content="width=device-width,initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no"/>
+<script type="text/javascript" src="${ctxStatic}/mark-new/js/jquery.min.js"></script>
+<script type="text/javascript" src="${ctxStatic}/mark-new/js/jquery-ui.min.js "></script>
+</head>
+<body>
+<canvas id="canvas"></canvas>
+</body>
+<script type="text/javascript">
+var imageServer = '${imageServer}';
+var urls = '${urls}'.split(',');
+var tags = JSON.parse('${tags}');
+var ctx;
+$(document).ready(function() {
+    var images = [];
+    var count = 0;
+    for(var i=0;i<urls.length;i++) {
+        var image = new Image();
+        images.push(image);
+        image.src = imageServer+urls[i];
+        image.onload = function(){
+            this.loaded = true;
+            count++;
+            
+            if(count==urls.length) {
+                render(images);
+            }
+        }
+    }
+});
+
+function render(images) {
+    var maxWidth=0;
+    var totalHeight=0;
+    for(var i=0;i<images.length;i++) {
+        images[i].left = 0;
+        images[i].top = totalHeight;
+        maxWidth = Math.max(maxWidth, images[i].width);
+        totalHeight += images[i].height;
+    }
+    
+    var canvas = $('#canvas')[0];
+    canvas.width = maxWidth;
+    canvas.height = totalHeight;
+    ctx = canvas.getContext('2d');
+    for(var i=0;i<images.length;i++) {
+        ctx.drawImage(images[i], 0, 0, images[i].width, images[i].height, images[i].left, images[i].top, images[i].width, images[i].height);
+    }
+    
+    for(var i=0;i<tags.length;i++) {
+        renderGroup(tags[i], images)
+    }
+}
+
+function renderGroup(group, images) {
+    var configs = group.config;
+    var tags = group.tags;
+    if(configs.length==0 || tags.length==0) {
+        return;
+    }
+    
+    var maxWidth = 0;
+    var totalHeight = 0;
+    // 计算评卷分组拼接图的总高度与最大宽度
+    for (var i=0;i<configs.length;i++) {
+        var config = configs[i];
+        if (config.w == 0 || config.h == 0) {
+            // 兼容老数据,宽高未设置时,表示直接使用整张裁切图
+            var image = images[config.i-1];
+            if(image!=undefined) {
+                config.w = image.width;
+                config.h = image.height;
+            }
+        }
+        if (config.w > 0 && config.h > 0) {
+            maxWidth = Math.max(maxWidth, config.w);
+            totalHeight += config.h;
+        }
+    }
+    
+    // 遍历所有显示元素
+    for (var i=0;i<tags.length;i++) {
+        var tag = tags[i];
+        // 计算显示元素在拼接图内的绝对位置
+        var left = maxWidth * tag.positionX;
+        var top = totalHeight * tag.positionY;
+        var start = 0;
+        for (var j=0;j<configs.length;j++) {
+            var config = configs[j];
+            if (config.w > 0 && config.h > 0) {
+                var image = images[config.i-1];
+                if (top <= (config.h + start) && image!=undefined) {
+                    // 根据绝对高度判断显示元素是否落在当前拼接块
+                    ctx.font ="60px Arial";
+                    ctx.fillStyle ='red';
+                    ctx.fillText(tag.content, left+config.x+image.left, top+config.y+image.top);
+                    break;
+                } else {
+                    start += config.h;
+                }
+            }
+        }
+    }
+}
+</script>
+</html>

+ 75 - 23
stmms-web/src/main/webapp/WEB-INF/views/modules/exam/tagInfo.jsp

@@ -44,45 +44,97 @@
 	<table id="contentTable" class="table table-striped table-bordered table-condensed">
 		<thead>
 			<tr>
-				<th>科目</th>
-				<th>学习中心</th>
+				<th>科目代码</th>
+                <th>大题号</th>
 				<th>准考证号</th>
-				<th>姓名</th>
-				<th>提交时间</th>
+				<th>状态</th>
+				<th>评卷员</th>
+                <th>评卷总分</th>
+                <th>给分明细</th>
+				<th>评卷时间</th>
 				<th>操作</th>
 			</tr>
 		</thead>
 		<tbody>
-		<c:forEach items="${resultList}" var="result">
-			<tr>
-				<td>${result.subjectCode}-${result.subjectName}</td>
-				<td>${result.campusName}</td>
-				<td>${result.examNumber}</td>
-				<td>${result.name}</td>
-				<td>${result.markTime}</td>
-				<td>
-					<a class="sheet-link" href="##" data-sheet-url="${result.sheetUrlString}" data-answer-url="<c:if test="${result.answerUrl!=null}">${cardServer}${result.answerUrl}</c:if>" data-title="${result.examNumber}&nbsp;&nbsp;${result.name}&nbsp;&nbsp;客观总分${result.objectiveScoreString}&nbsp;&nbsp;主观总分${result.subjectiveScoreString}&nbsp;&nbsp;全卷总分${result.totalScoreString}">原图</a>
-				</td>
-			</tr>
-		</c:forEach>
-		</tbody>
+        <c:forEach items="${query.result}" var="result">
+            <tr>
+                <td>${result.subjectCode}</td>
+                <td>${result.groupNumber}</td>
+                <td>${result.examNumber}</td>
+                <td>${result.status.name}</td>
+                <td>
+                    <c:if test="${result.marker!=null}">
+                    ${result.marker.loginName}
+                    </c:if>
+                    <c:if test="${result.marker==null}">
+                    &nbsp;
+                    </c:if>
+                </td>
+                <td>
+                    <c:if test="${result.markerScore!=null}">
+                    <fmt:formatNumber pattern="###.#" value="${result.markerScore}"/>
+                    </c:if>
+                    <c:if test="${result.markerScore==null}">
+                    &nbsp;
+                    </c:if>
+                </td>
+                <td>
+                    <c:if test="${result.markerScoreList!=null}">
+                    ${result.markerScoreList}
+                    </c:if>
+                    <c:if test="${result.markerScoreList==null}">
+                    &nbsp;
+                    </c:if>
+                </td>
+                <td>
+                    <c:if test="${result.markerTime!=null}">
+                    <fmt:formatDate value="${result.markerTime}" pattern="yyyy-MM-dd HH:mm:ss" />
+                    </c:if>
+                    <c:if test="${result.markerTime==null}">
+                    &nbsp;
+                    </c:if>
+                </td>
+                <td>
+                    <c:if test="${result.status.value==1 || result.status.value==3}">
+                    <a class="track-link" href="##" data-image-url="${ctx}/admin/exam/track/byLibrary?libraryId=${result.id}" data-title="${result.examNumber}">阅卷轨迹</a>
+                    </c:if>
+                    <c:if test="${result.status.value==1}">
+                    &nbsp;
+                    <a href="##" data-id="${result.id}" class="back-link">打回</a>
+                    </c:if>
+                </td>
+            </tr>
+        </c:forEach>
+        </tbody>
 	</table>
 	<div class="pagination">${query}</div>
+	<%@include file="/WEB-INF/views/include/trackView.jsp" %>
 	<%@include file="/WEB-INF/views/include/imageView.jsp" %>
 <script type="text/javascript">
 var searchSubjectCode = '${query.subjectCode}';
 var searchGroupNumber = '${query.groupNumber}';
 $(document).ready(function() {
-    /* new jBox('Image', {
-    	imageFade: 0,
-    	delayOpen: 0,
-    	delayClose: 0,
-    	maxHeight: $(window).height()*0.88
-    }); */
     $('.sheet-link').click(function(){
     	initImagePopover($(this).attr('data-title'), '${imageServer}', $(this).attr('data-sheet-url'), $(this).attr('data-answer-url'));
     	return false;
     });
+    $('.back-link').click(function(){
+        if(!confirm('确定要打回该评卷任务吗?')){
+            return;
+        }
+        $.post('${ctx}/admin/exam/library/back', {id: $(this).attr('data-id')}, function(result){
+            if(result.success==true){
+                alert('打回成功');
+                $("#searchForm").submit();
+            }else{
+                alert(result.message);
+            }
+        });
+    });
+    $('.track-link').click(function(){
+        initTrackPopover($(this).attr('data-title'),$(this).attr('data-image-url'));
+        return false;
+    });
 
     $('#subject-select').change(function(){
         var code = $(this).val();