Kaynağa Gözat

3.3.0 仲裁结果保存

xiaofei 1 yıl önce
ebeveyn
işleme
916b6385f3
26 değiştirilmiş dosya ile 1056 ekleme ve 109 silme
  1. 12 4
      distributed-print/src/main/java/com/qmth/distributed/print/api/mark/MarkArbitrateController.java
  2. 116 0
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/dto/mark/SpecialTagDTO.java
  3. 9 13
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/dto/mark/manage/TrackDTO.java
  4. 55 24
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/entity/MarkGroup.java
  5. 93 47
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/entity/MarkStudent.java
  6. 34 0
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/entity/MarkTask.java
  7. 34 0
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/enums/ScorePolicy.java
  8. 192 0
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/params/MarkResult.java
  9. 3 0
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/MarkArbitrateHistoryService.java
  10. 2 0
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/MarkGroupStudentService.java
  11. 4 1
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/MarkHeaderTrackService.java
  12. 2 0
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/MarkQuestionService.java
  13. 5 0
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/MarkService.java
  14. 1 1
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/MarkStudentService.java
  15. 3 0
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/MarkSubjectiveScoreService.java
  16. 2 0
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/MarkTaskService.java
  17. 28 0
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkArbitrateHistoryServiceImpl.java
  18. 1 1
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkGroupServiceImpl.java
  19. 10 1
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkGroupStudentServiceImpl.java
  20. 12 0
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkHeaderTrackServiceImpl.java
  21. 10 0
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkQuestionServiceImpl.java
  22. 246 12
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkServiceImpl.java
  23. 1 1
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkStudentServiceImpl.java
  24. 14 1
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkSubjectiveScoreServiceImpl.java
  25. 18 3
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkTaskServiceImpl.java
  26. 149 0
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/utils/BigDecimalUtils.java

+ 12 - 4
distributed-print/src/main/java/com/qmth/distributed/print/api/mark/MarkArbitrateController.java

@@ -10,14 +10,12 @@ import com.qmth.teachcloud.common.contant.SystemConstant;
 import com.qmth.teachcloud.common.util.Result;
 import com.qmth.teachcloud.common.util.ResultUtil;
 import com.qmth.teachcloud.mark.dto.mark.manage.Task;
+import com.qmth.teachcloud.mark.params.MarkResult;
 import com.qmth.teachcloud.mark.service.MarkArbitrateHistoryService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiParam;
-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.RestController;
+import org.springframework.web.bind.annotation.*;
 
 import javax.annotation.Resource;
 import javax.validation.constraints.Max;
@@ -93,4 +91,14 @@ public class MarkArbitrateController {
         Task task = markArbitrateHistoryService.getArbitrateTask(arbitrateId);
         return ResultUtil.ok(task);
     }
+
+    /**
+     * 保存任务
+     */
+    @ApiOperation(value = "保存任务")
+    @RequestMapping(value = "/saveTask", method = RequestMethod.POST)
+    public Result saveTask(@RequestBody MarkResult markResult) {
+        markArbitrateHistoryService.saveArbitrateTask(markResult);
+        return ResultUtil.ok(true);
+    }
 }

+ 116 - 0
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/dto/mark/SpecialTagDTO.java

@@ -0,0 +1,116 @@
+package com.qmth.teachcloud.mark.dto.mark;
+
+import java.io.Serializable;
+
+public class SpecialTagDTO implements Serializable {
+
+    private static final long serialVersionUID = -5424015292124065736L;
+
+    private String tagName;
+
+    private Double positionX;
+
+    private Double positionY;
+
+    private Integer offsetIndex;
+
+    private Integer offsetX;
+
+    private Integer offsetY;
+
+    public SpecialTagDTO() {
+
+    }
+
+//    public SpecialTagDTO(MarkSpecialTag markSpecialTag) {
+//        this.tagName = markSpecialTag.getTagName();
+//        this.positionX = markSpecialTag.getPositionX();
+//        this.positionY = markSpecialTag.getPositionY();
+//        this.offsetIndex = markSpecialTag.getOffsetIndex();
+//        this.offsetX = markSpecialTag.getOffsetX();
+//        this.offsetY = markSpecialTag.getOffsetY();
+//    }
+
+//    public SpecialTagDTO(HeaderTag tag) {
+//        this.tagName = tag.getTagName();
+//        this.positionX = tag.getPositionX();
+//        this.positionY = tag.getPositionY();
+//        this.offsetIndex = tag.getOffsetIndex();
+//        this.offsetX = tag.getOffsetX();
+//        this.offsetY = tag.getOffsetY();
+//    }
+
+    public MarkSpecialTag transform(MarkLibrary library) {
+        MarkSpecialTag markSpecialTag = new MarkSpecialTag();
+        markSpecialTag.setLibraryId(library.getId());
+        markSpecialTag.setTagName(tagName);
+        markSpecialTag.setPositionX(positionX);
+        markSpecialTag.setPositionY(positionY);
+        markSpecialTag.setOffsetIndex(offsetIndex);
+        markSpecialTag.setOffsetX(offsetX);
+        markSpecialTag.setOffsetY(offsetY);
+        return markSpecialTag;
+    }
+
+    public HeaderTag transform(ArbitrateHistory library) {
+        HeaderTag markSpecialTag = new HeaderTag();
+        markSpecialTag.setStudentId(library.getStudentId());
+        markSpecialTag.setGroupNumber(library.getGroupNumber());
+        markSpecialTag.setUserId(library.getUserId());
+        markSpecialTag.setTagName(tagName);
+        markSpecialTag.setPositionX(positionX);
+        markSpecialTag.setPositionY(positionY);
+        markSpecialTag.setOffsetIndex(offsetIndex);
+        markSpecialTag.setOffsetX(offsetX);
+        markSpecialTag.setOffsetY(offsetY);
+        return markSpecialTag;
+    }
+
+    public String getTagName() {
+        return tagName;
+    }
+
+    public void setTagName(String tagName) {
+        this.tagName = tagName;
+    }
+
+    public Double getPositionX() {
+        return positionX;
+    }
+
+    public void setPositionX(Double positionX) {
+        this.positionX = positionX;
+    }
+
+    public Double getPositionY() {
+        return positionY;
+    }
+
+    public void setPositionY(Double positionY) {
+        this.positionY = positionY;
+    }
+
+    public Integer getOffsetIndex() {
+        return offsetIndex;
+    }
+
+    public void setOffsetIndex(Integer offsetIndex) {
+        this.offsetIndex = offsetIndex;
+    }
+
+    public void setOffsetX(Integer offsetX) {
+        this.offsetX = offsetX;
+    }
+
+    public Integer getOffsetX() {
+        return offsetX;
+    }
+
+    public Integer getOffsetY() {
+        return offsetY;
+    }
+
+    public void setOffsetY(Integer offsetY) {
+        this.offsetY = offsetY;
+    }
+}

+ 9 - 13
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/dto/mark/manage/TrackDTO.java

@@ -1,9 +1,6 @@
 package com.qmth.teachcloud.mark.dto.mark.manage;
 
-import com.qmth.teachcloud.mark.entity.MarkHeaderTrack;
-import com.qmth.teachcloud.mark.entity.MarkTask;
-import com.qmth.teachcloud.mark.entity.MarkTrack;
-import com.qmth.teachcloud.mark.entity.MarkUserGroup;
+import com.qmth.teachcloud.mark.entity.*;
 
 import java.io.Serializable;
 
@@ -87,24 +84,23 @@ public class TrackDTO implements Serializable {
         return track;
     }
 
-    /*public HeaderTrack transform(ArbitrateHistory library) {
-        HeaderTrack track = new HeaderTrack();
+    public MarkHeaderTrack transform(MarkArbitrateHistory history) {
+        MarkHeaderTrack track = new MarkHeaderTrack();
         track.setQuestionNumber(getMainNumber() + "." + getSubNumber());
         track.setNumber(getNumber());
-        track.setStudentId(library.getStudentId());
-        track.setExamId(library.getExamId());
-        track.setSubjectCode(library.getSubjectCode());
-        track.setGroupNumber(library.getGroupNumber());
-        track.setUserId(library.getUserId());
+        track.setStudentId(history.getStudentId());
+        track.setExamId(history.getExamId());
+        track.setPaperNumber(history.getPaperNumber());
+        track.setGroupNumber(history.getGroupNumber());
+        track.setUserId(history.getUpdateUserId());
         track.setScore(getScore());
         track.setPositionX(getPositionX());
         track.setPositionY(getPositionY());
         track.setOffsetIndex(getOffsetIndex());
         track.setOffsetX(getOffsetX());
         track.setOffsetY(getOffsetY());
-        track.setUnanswered(isUnanswered());
         return track;
-    }*/
+    }
 
     public Integer getMainNumber() {
         return mainNumber;

+ 55 - 24
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/entity/MarkGroup.java

@@ -1,20 +1,22 @@
 package com.qmth.teachcloud.mark.entity;
 
 import com.baomidou.mybatisplus.annotation.TableField;
-import com.baomidou.mybatisplus.annotation.TableName;
 import com.baomidou.mybatisplus.annotation.TableId;
-import java.io.Serializable;
-import java.text.DecimalFormat;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Set;
-
+import com.baomidou.mybatisplus.annotation.TableName;
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import com.qmth.teachcloud.mark.dto.mark.ScoreItem;
+import com.qmth.teachcloud.mark.enums.ScorePolicy;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import org.apache.commons.lang3.StringUtils;
 
+import java.io.Serializable;
+import java.text.DecimalFormat;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
 /**
  * <p>
  * 评卷分组表
@@ -24,7 +26,7 @@ import org.apache.commons.lang3.StringUtils;
  * @since 2023-09-22
  */
 @TableName("mark_group")
-@ApiModel(value="MarkGroup对象", description="评卷分组表")
+@ApiModel(value = "MarkGroup对象", description = "评卷分组表")
 public class MarkGroup implements Serializable {
 
     private static final long serialVersionUID = 1L;
@@ -59,7 +61,7 @@ public class MarkGroup implements Serializable {
     private Double arbitrateThreshold;
 
     @ApiModelProperty(value = "合分策略")
-    private String scorePolicy;
+    private ScorePolicy scorePolicy;
 
     @ApiModelProperty(value = "任务总量")
     private Integer taskCount;
@@ -96,6 +98,12 @@ public class MarkGroup implements Serializable {
     @TableField(exist = false)
     private String scoreList;
 
+    @TableField(exist = false)
+    private double markScore;
+
+    @TableField(exist = false)
+    private List<ScoreItem> markScoreDetail;
+
     public Long getExamId() {
         return examId;
     }
@@ -127,6 +135,7 @@ public class MarkGroup implements Serializable {
     public void setPaperNumber(String paperNumber) {
         this.paperNumber = paperNumber;
     }
+
     public Integer getNumber() {
         return number;
     }
@@ -134,6 +143,7 @@ public class MarkGroup implements Serializable {
     public void setNumber(Integer number) {
         this.number = number;
     }
+
     public String getPicList() {
         return picList;
     }
@@ -141,6 +151,7 @@ public class MarkGroup implements Serializable {
     public void setPicList(String picList) {
         this.picList = picList;
     }
+
     public Double getTotalScore() {
         return totalScore;
     }
@@ -148,6 +159,7 @@ public class MarkGroup implements Serializable {
     public void setTotalScore(Double totalScore) {
         this.totalScore = totalScore;
     }
+
     public Double getDoubleRate() {
         return doubleRate;
     }
@@ -155,6 +167,7 @@ public class MarkGroup implements Serializable {
     public void setDoubleRate(Double doubleRate) {
         this.doubleRate = doubleRate;
     }
+
     public Double getArbitrateThreshold() {
         return arbitrateThreshold;
     }
@@ -162,11 +175,12 @@ public class MarkGroup implements Serializable {
     public void setArbitrateThreshold(Double arbitrateThreshold) {
         this.arbitrateThreshold = arbitrateThreshold;
     }
-    public String getScorePolicy() {
+
+    public ScorePolicy getScorePolicy() {
         return scorePolicy;
     }
 
-    public void setScorePolicy(String scorePolicy) {
+    public void setScorePolicy(ScorePolicy scorePolicy) {
         this.scorePolicy = scorePolicy;
     }
 
@@ -185,6 +199,7 @@ public class MarkGroup implements Serializable {
     public void setMarkedCount(Integer markedCount) {
         this.markedCount = markedCount;
     }
+
     public Integer getLeftCount() {
         return leftCount;
     }
@@ -233,6 +248,22 @@ public class MarkGroup implements Serializable {
         this.scoreList = scoreList;
     }
 
+    public double getMarkScore() {
+        return markScore;
+    }
+
+    public void setMarkScore(double markScore) {
+        this.markScore = markScore;
+    }
+
+    public List<ScoreItem> getMarkScoreDetail() {
+        return markScoreDetail;
+    }
+
+    public void setMarkScoreDetail(List<ScoreItem> markScoreDetail) {
+        this.markScoreDetail = markScoreDetail;
+    }
+
     public void setQuestionList(List<MarkQuestion> questionList) {
         DecimalFormat format = new DecimalFormat("####.###");
         Set<Integer> mainNumbers = new LinkedHashSet<>();
@@ -260,18 +291,18 @@ public class MarkGroup implements Serializable {
     @Override
     public String toString() {
         return "MarkGroup{" +
-            "examId=" + examId +
-            ", courseCode=" + courseCode +
-            ", paperNumber=" + paperNumber +
-            ", number=" + number +
-            ", picList=" + picList +
-            ", totalScore=" + totalScore +
-            ", doubleRate=" + doubleRate +
-            ", arbitrateThreshold=" + arbitrateThreshold +
-            ", scorePolicy=" + scorePolicy +
-            ", taskCount=" + taskCount +
-            ", markedCount=" + markedCount +
-            ", leftCount=" + leftCount +
-        "}";
+                "examId=" + examId +
+                ", courseCode=" + courseCode +
+                ", paperNumber=" + paperNumber +
+                ", number=" + number +
+                ", picList=" + picList +
+                ", totalScore=" + totalScore +
+                ", doubleRate=" + doubleRate +
+                ", arbitrateThreshold=" + arbitrateThreshold +
+                ", scorePolicy=" + scorePolicy +
+                ", taskCount=" + taskCount +
+                ", markedCount=" + markedCount +
+                ", leftCount=" + leftCount +
+                "}";
     }
 }

+ 93 - 47
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/entity/MarkStudent.java

@@ -1,6 +1,7 @@
 package com.qmth.teachcloud.mark.entity;
 
 import java.io.Serializable;
+import java.util.List;
 
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
@@ -8,8 +9,10 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
 import com.qmth.teachcloud.common.enums.ScanStatus;
 
+import com.qmth.teachcloud.mark.dto.mark.ScoreItem;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
+import org.apache.commons.lang3.StringUtils;
 
 /**
  * <p>
@@ -20,7 +23,7 @@ import io.swagger.annotations.ApiModelProperty;
  * @since 2023-09-22
  */
 @TableName("mark_student")
-@ApiModel(value="MarkStudent对象", description="考试考生库")
+@ApiModel(value = "MarkStudent对象", description = "考试考生库")
 public class MarkStudent implements Serializable {
 
     private static final long serialVersionUID = 1L;
@@ -133,7 +136,7 @@ public class MarkStudent implements Serializable {
     private String breachCode;
 
     private Boolean omrAbsent;
-    
+
     private Integer cardNumber;
 
     public MarkStudent() {
@@ -160,6 +163,7 @@ public class MarkStudent implements Serializable {
     public void setId(Long id) {
         this.id = id;
     }
+
     public Long getExamId() {
         return examId;
     }
@@ -167,6 +171,7 @@ public class MarkStudent implements Serializable {
     public void setExamId(Long examId) {
         this.examId = examId;
     }
+
     public String getCourseCode() {
         return courseCode;
     }
@@ -174,6 +179,7 @@ public class MarkStudent implements Serializable {
     public void setCourseCode(String courseCode) {
         this.courseCode = courseCode;
     }
+
     public String getCourseName() {
         return courseName;
     }
@@ -181,6 +187,7 @@ public class MarkStudent implements Serializable {
     public void setCourseName(String courseName) {
         this.courseName = courseName;
     }
+
     public String getPaperNumber() {
         return paperNumber;
     }
@@ -188,6 +195,7 @@ public class MarkStudent implements Serializable {
     public void setPaperNumber(String paperNumber) {
         this.paperNumber = paperNumber;
     }
+
     public String getSecretNumber() {
         return secretNumber;
     }
@@ -195,6 +203,7 @@ public class MarkStudent implements Serializable {
     public void setSecretNumber(String secretNumber) {
         this.secretNumber = secretNumber;
     }
+
     public String getStudentCode() {
         return studentCode;
     }
@@ -202,6 +211,7 @@ public class MarkStudent implements Serializable {
     public void setStudentCode(String studentCode) {
         this.studentCode = studentCode;
     }
+
     public String getStudentName() {
         return studentName;
     }
@@ -209,6 +219,7 @@ public class MarkStudent implements Serializable {
     public void setStudentName(String studentName) {
         this.studentName = studentName;
     }
+
     public String getPackageCode() {
         return packageCode;
     }
@@ -216,6 +227,7 @@ public class MarkStudent implements Serializable {
     public void setPackageCode(String packageCode) {
         this.packageCode = packageCode;
     }
+
     public String getExamPlace() {
         return examPlace;
     }
@@ -223,6 +235,7 @@ public class MarkStudent implements Serializable {
     public void setExamPlace(String examPlace) {
         this.examPlace = examPlace;
     }
+
     public String getExamRoom() {
         return examRoom;
     }
@@ -230,6 +243,7 @@ public class MarkStudent implements Serializable {
     public void setExamRoom(String examRoom) {
         this.examRoom = examRoom;
     }
+
     public String getRemark() {
         return remark;
     }
@@ -237,6 +251,7 @@ public class MarkStudent implements Serializable {
     public void setRemark(String remark) {
         this.remark = remark;
     }
+
     public String getBatchCode() {
         return batchCode;
     }
@@ -244,6 +259,7 @@ public class MarkStudent implements Serializable {
     public void setBatchCode(String batchCode) {
         this.batchCode = batchCode;
     }
+
     public Integer getSheetCount() {
         return sheetCount;
     }
@@ -251,6 +267,7 @@ public class MarkStudent implements Serializable {
     public void setSheetCount(Integer sheetCount) {
         this.sheetCount = sheetCount;
     }
+
     public String getAnswers() {
         return answers;
     }
@@ -258,6 +275,7 @@ public class MarkStudent implements Serializable {
     public void setAnswers(String answers) {
         this.answers = answers;
     }
+
     public Integer getIsUpload() {
         return isUpload;
     }
@@ -265,6 +283,7 @@ public class MarkStudent implements Serializable {
     public void setIsUpload(Integer isUpload) {
         this.isUpload = isUpload;
     }
+
     public Integer getIsAbsent() {
         return isAbsent;
     }
@@ -272,6 +291,7 @@ public class MarkStudent implements Serializable {
     public void setIsAbsent(Integer isAbsent) {
         this.isAbsent = isAbsent;
     }
+
     public Integer getIsManualAbsent() {
         return isManualAbsent;
     }
@@ -279,6 +299,7 @@ public class MarkStudent implements Serializable {
     public void setIsManualAbsent(Integer isManualAbsent) {
         this.isManualAbsent = isManualAbsent;
     }
+
     public Integer getIsBreach() {
         return isBreach;
     }
@@ -286,6 +307,7 @@ public class MarkStudent implements Serializable {
     public void setIsBreach(Integer isBreach) {
         this.isBreach = isBreach;
     }
+
     public Long getUploadTime() {
         return uploadTime;
     }
@@ -293,6 +315,7 @@ public class MarkStudent implements Serializable {
     public void setUploadTime(Long uploadTime) {
         this.uploadTime = uploadTime;
     }
+
     public Long getInspectTime() {
         return inspectTime;
     }
@@ -300,6 +323,7 @@ public class MarkStudent implements Serializable {
     public void setInspectTime(Long inspectTime) {
         this.inspectTime = inspectTime;
     }
+
     public Long getInspectorId() {
         return inspectorId;
     }
@@ -307,6 +331,7 @@ public class MarkStudent implements Serializable {
     public void setInspectorId(Long inspectorId) {
         this.inspectorId = inspectorId;
     }
+
     public Double getObjectiveScore() {
         return objectiveScore;
     }
@@ -314,6 +339,7 @@ public class MarkStudent implements Serializable {
     public void setObjectiveScore(Double objectiveScore) {
         this.objectiveScore = objectiveScore;
     }
+
     public String getObjectiveScoreList() {
         return objectiveScoreList;
     }
@@ -321,6 +347,7 @@ public class MarkStudent implements Serializable {
     public void setObjectiveScoreList(String objectiveScoreList) {
         this.objectiveScoreList = objectiveScoreList;
     }
+
     public String getSubjectiveStatus() {
         return subjectiveStatus;
     }
@@ -328,6 +355,7 @@ public class MarkStudent implements Serializable {
     public void setSubjectiveStatus(String subjectiveStatus) {
         this.subjectiveStatus = subjectiveStatus;
     }
+
     public Double getSubjectiveScore() {
         return subjectiveScore;
     }
@@ -335,6 +363,7 @@ public class MarkStudent implements Serializable {
     public void setSubjectiveScore(Double subjectiveScore) {
         this.subjectiveScore = subjectiveScore;
     }
+
     public String getSubjectiveScoreList() {
         return subjectiveScoreList;
     }
@@ -342,6 +371,7 @@ public class MarkStudent implements Serializable {
     public void setSubjectiveScoreList(String subjectiveScoreList) {
         this.subjectiveScoreList = subjectiveScoreList;
     }
+
     public String getCollege() {
         return college;
     }
@@ -349,6 +379,7 @@ public class MarkStudent implements Serializable {
     public void setCollege(String college) {
         this.college = college;
     }
+
     public String getClassName() {
         return className;
     }
@@ -356,6 +387,7 @@ public class MarkStudent implements Serializable {
     public void setClassName(String className) {
         this.className = className;
     }
+
     public String getTeacher() {
         return teacher;
     }
@@ -363,6 +395,7 @@ public class MarkStudent implements Serializable {
     public void setTeacher(String teacher) {
         this.teacher = teacher;
     }
+
     public ScanStatus getScanStatus() {
         return scanStatus;
     }
@@ -370,6 +403,7 @@ public class MarkStudent implements Serializable {
     public void setScanStatus(ScanStatus scanStatus) {
         this.scanStatus = scanStatus;
     }
+
     public Boolean getQuestionFilled() {
         return questionFilled;
     }
@@ -377,6 +411,7 @@ public class MarkStudent implements Serializable {
     public void setQuestionFilled(Boolean questionFilled) {
         this.questionFilled = questionFilled;
     }
+
     public Boolean getAssigned() {
         return assigned;
     }
@@ -384,6 +419,7 @@ public class MarkStudent implements Serializable {
     public void setAssigned(Boolean assigned) {
         this.assigned = assigned;
     }
+
     public Boolean getAbsentSuspect() {
         return absentSuspect;
     }
@@ -391,6 +427,7 @@ public class MarkStudent implements Serializable {
     public void setAbsentSuspect(Boolean absentSuspect) {
         this.absentSuspect = absentSuspect;
     }
+
     public Boolean getIncomplete() {
         return incomplete;
     }
@@ -398,6 +435,7 @@ public class MarkStudent implements Serializable {
     public void setIncomplete(Boolean incomplete) {
         this.incomplete = incomplete;
     }
+
     public String getBreachCode() {
         return breachCode;
     }
@@ -415,54 +453,62 @@ public class MarkStudent implements Serializable {
     }
 
     public Integer getCardNumber() {
-		return cardNumber;
-	}
+        return cardNumber;
+    }
 
-	public void setCardNumber(Integer cardNumber) {
-		this.cardNumber = cardNumber;
-	}
+    public void setCardNumber(Integer cardNumber) {
+        this.cardNumber = cardNumber;
+    }
+
+    public static String buildScoreList(List<ScoreItem> scoreList) {
+        if (scoreList != null) {
+            return StringUtils.join(scoreList, ";");
+        } else {
+            return null;
+        }
+    }
 
-	@Override
+    @Override
     public String toString() {
         return "MarkStudent{" +
-            "id=" + id +
-            ", examId=" + examId +
-            ", courseCode=" + courseCode +
-            ", courseName=" + courseName +
-            ", paperNumber=" + paperNumber +
-            ", secretNumber=" + secretNumber +
-            ", studentCode=" + studentCode +
-            ", studentName=" + studentName +
-            ", packageCode=" + packageCode +
-            ", examPlace=" + examPlace +
-            ", examRoom=" + examRoom +
-            ", remark=" + remark +
-            ", batchCode=" + batchCode +
-            ", sheetCount=" + sheetCount +
-            ", answers=" + answers +
-            ", isUpload=" + isUpload +
-            ", isAbsent=" + isAbsent +
-            ", isManualAbsent=" + isManualAbsent +
-            ", isBreach=" + isBreach +
-            ", uploadTime=" + uploadTime +
-            ", inspectTime=" + inspectTime +
-            ", inspectorId=" + inspectorId +
-            ", objectiveScore=" + objectiveScore +
-            ", objectiveScoreList=" + objectiveScoreList +
-            ", subjectiveStatus=" + subjectiveStatus +
-            ", subjectiveScore=" + subjectiveScore +
-            ", subjectiveScoreList=" + subjectiveScoreList +
-            ", college=" + college +
-            ", className=" + className +
-            ", teacher=" + teacher +
-            ", scanStatus=" + scanStatus +
-            ", questionFilled=" + questionFilled +
-            ", assigned=" + assigned +
-            ", absentSuspect=" + absentSuspect +
-            ", incomplete=" + incomplete +
-            ", breachCode=" + breachCode +
-            ", omrAbsent=" + omrAbsent +
-            ", cardNumber=" + cardNumber +
-        "}";
+                "id=" + id +
+                ", examId=" + examId +
+                ", courseCode=" + courseCode +
+                ", courseName=" + courseName +
+                ", paperNumber=" + paperNumber +
+                ", secretNumber=" + secretNumber +
+                ", studentCode=" + studentCode +
+                ", studentName=" + studentName +
+                ", packageCode=" + packageCode +
+                ", examPlace=" + examPlace +
+                ", examRoom=" + examRoom +
+                ", remark=" + remark +
+                ", batchCode=" + batchCode +
+                ", sheetCount=" + sheetCount +
+                ", answers=" + answers +
+                ", isUpload=" + isUpload +
+                ", isAbsent=" + isAbsent +
+                ", isManualAbsent=" + isManualAbsent +
+                ", isBreach=" + isBreach +
+                ", uploadTime=" + uploadTime +
+                ", inspectTime=" + inspectTime +
+                ", inspectorId=" + inspectorId +
+                ", objectiveScore=" + objectiveScore +
+                ", objectiveScoreList=" + objectiveScoreList +
+                ", subjectiveStatus=" + subjectiveStatus +
+                ", subjectiveScore=" + subjectiveScore +
+                ", subjectiveScoreList=" + subjectiveScoreList +
+                ", college=" + college +
+                ", className=" + className +
+                ", teacher=" + teacher +
+                ", scanStatus=" + scanStatus +
+                ", questionFilled=" + questionFilled +
+                ", assigned=" + assigned +
+                ", absentSuspect=" + absentSuspect +
+                ", incomplete=" + incomplete +
+                ", breachCode=" + breachCode +
+                ", omrAbsent=" + omrAbsent +
+                ", cardNumber=" + cardNumber +
+                "}";
     }
 }

+ 34 - 0
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/entity/MarkTask.java

@@ -3,11 +3,15 @@ package com.qmth.teachcloud.mark.entity;
 import com.baomidou.mybatisplus.annotation.*;
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import com.qmth.teachcloud.mark.dto.mark.ScoreItem;
 import com.qmth.teachcloud.mark.enums.MarkTaskStatus;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
+import org.apache.commons.lang3.StringUtils;
 
 import java.io.Serializable;
+import java.util.LinkedList;
+import java.util.List;
 
 /**
  * <p>
@@ -237,6 +241,36 @@ public class MarkTask implements Serializable {
         this.headerScoreList = headerScoreList;
     }
 
+    public List<ScoreItem> getScoreList() {
+        List<ScoreItem> list = new LinkedList<ScoreItem>();
+        String scoreList = null;
+        if (StringUtils.isNotBlank(headerScoreList)) {
+            scoreList = headerScoreList;
+        } else if (StringUtils.isNotBlank(markerScoreList)) {
+            scoreList = markerScoreList;
+        }
+        if (StringUtils.isNotBlank(scoreList)) {
+            try {
+                String[] values = scoreList.split(",");
+                for (String value : values) {
+                    if (value.equals("#")) {
+                        list.add(new ScoreItem(false));
+                    } else {
+                        ScoreItem item = ScoreItem.parse(value, false);
+                        if (item != null) {
+                            list.add(item);
+                        }
+                    }
+                }
+                if (scoreList.endsWith(",")) {
+                    list.add(new ScoreItem(false));
+                }
+            } catch (Exception e) {
+            }
+        }
+        return list;
+    }
+
     @Override
     public String toString() {
         return "MarkTask{" +

+ 34 - 0
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/enums/ScorePolicy.java

@@ -0,0 +1,34 @@
+package com.qmth.teachcloud.mark.enums;
+
+/**
+ * 多评情况下的合分策略
+ */
+public enum ScorePolicy {
+    AVG("平均分", 1), MAX("最高分", 2), MIN("最低分", 3);
+
+    private String name;
+
+    private int value;
+
+    private ScorePolicy(String name, int value) {
+        this.name = name;
+        this.value = value;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public int getValue() {
+        return value;
+    }
+
+    public static ScorePolicy findByValue(int value) {
+        for (ScorePolicy c : ScorePolicy.values()) {
+            if (c.getValue() == value) {
+                return c;
+            }
+        }
+        return null;
+    }
+}

+ 192 - 0
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/params/MarkResult.java

@@ -0,0 +1,192 @@
+package com.qmth.teachcloud.mark.params;
+
+import com.qmth.teachcloud.mark.dto.mark.manage.TrackDTO;
+import com.qmth.teachcloud.mark.entity.*;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * 标准评卷结果对象
+ * 
+ * @author luoshi
+ *
+ */
+public class MarkResult {
+
+    public static final String SPLIT = ",";
+
+    /**
+     * 评卷状态
+     */
+    private String statusValue;
+
+    /**
+     * 考生编号
+     */
+    private Integer studentId;
+
+    /**
+     * 评卷任务编号
+     */
+    private Integer libraryId;
+
+    /**
+     * 总分
+     */
+    private double markerScore;
+
+    /**
+     * 分值列表
+     */
+    private Double[] scoreList;
+
+    /**
+     * 阅卷轨迹列表
+     */
+    private TrackDTO[] trackList;
+
+    /**
+     * 特殊标记列表
+     */
+//    private SpecialTagDTO[] specialTagList;
+
+    /**
+     * 所花时间
+     */
+    private int spent;
+
+    /**
+     * 是否问题卷
+     */
+    private boolean isProblem;
+
+    /**
+     * 问题类型
+     */
+    private Integer problemTypeId;
+
+    private boolean unselective;
+
+    public String getStatusValue() {
+        return statusValue;
+    }
+
+    public void setStatusValue(String statusValue) {
+        this.statusValue = statusValue;
+    }
+
+    public Integer getLibraryId() {
+        return libraryId;
+    }
+
+    public void setLibraryId(Integer libraryId) {
+        this.libraryId = libraryId;
+    }
+
+    public double getMarkerScore() {
+        return markerScore;
+    }
+
+    public void setMarkerScore(double markerScore) {
+        this.markerScore = markerScore;
+    }
+
+    public String getScoreList() {
+        List<Object> list = new ArrayList<Object>();
+        for (int i = 0; i < scoreList.length; i++) {
+            Double d = scoreList[i];
+            if (d % 1 == 0) {
+                list.add(d.intValue());
+            } else {
+                list.add(d);
+            }
+        }
+        return StringUtils.join(list, SPLIT);
+    }
+
+    public void setScoreList(Double[] scoreList) {
+        this.scoreList = scoreList;
+    }
+
+    public TrackDTO[] getTrackList() {
+        return trackList;
+    }
+
+    public void setTrackList(TrackDTO[] trackList) {
+        this.trackList = trackList;
+    }
+
+    public int getSpent() {
+        return spent;
+    }
+
+    public void setSpent(int spent) {
+        this.spent = spent;
+    }
+
+    public Integer getStudentId() {
+        return studentId;
+    }
+
+    public void setStudentId(Integer studentId) {
+        this.studentId = studentId;
+    }
+
+    public List<MarkHeaderTrack> getTrackList(MarkArbitrateHistory history) {
+        List<MarkHeaderTrack> list = new LinkedList<>();
+        if (trackList != null) {
+            for (TrackDTO dto : trackList) {
+                list.add(dto.transform(history));
+            }
+        }
+        return list;
+    }
+
+    public List<MarkTrack> getTrackList(MarkTask markTask, MarkUserGroup markUserGroup) {
+        List<MarkTrack> list = new LinkedList<>();
+        if (trackList != null) {
+            for (TrackDTO dto : trackList) {
+                list.add(dto.transform(markTask, markUserGroup));
+            }
+        }
+        return list;
+    }
+
+//    public List<MarkHeaderTrack> getHeaderTagList(MarkArbitrateHistory library) {
+//        List<MarkHeaderTrack> list = new LinkedList<>();
+//        if (specialTagList != null) {
+//            for (SpecialTagDTO dto : specialTagList) {
+//                list.add(dto.transform(library));
+//            }
+//        }
+//        return list;
+//    }
+
+    public boolean isProblem() {
+        return isProblem;
+    }
+
+    public void setProblem(boolean isProblem) {
+        this.isProblem = isProblem;
+    }
+
+    public Integer getProblemTypeId() {
+        return problemTypeId;
+    }
+
+    public void setProblemTypeId(Integer problemTypeId) {
+        this.problemTypeId = problemTypeId;
+    }
+
+    public boolean isUnselective() {
+        return unselective;
+    }
+
+    public void setUnselective(boolean unselective) {
+        this.unselective = unselective;
+    }
+
+}

+ 3 - 0
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/MarkArbitrateHistoryService.java

@@ -7,6 +7,7 @@ import com.qmth.teachcloud.mark.dto.mark.manage.MarkArbitrateSettingDto;
 import com.qmth.teachcloud.mark.dto.mark.manage.Task;
 import com.qmth.teachcloud.mark.entity.MarkArbitrateHistory;
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.qmth.teachcloud.mark.params.MarkResult;
 
 import java.util.List;
 
@@ -29,4 +30,6 @@ public interface MarkArbitrateHistoryService extends IService<MarkArbitrateHisto
     MarkArbitrateSettingDto getArbitrateSetting(Long arbitrateId);
 
     Task getArbitrateTask(Long arbitrateId);
+
+    void saveArbitrateTask(MarkResult markResult);
 }

+ 2 - 0
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/MarkGroupStudentService.java

@@ -1,5 +1,6 @@
 package com.qmth.teachcloud.mark.service;
 
+import com.qmth.teachcloud.common.enums.mark.SubjectiveStatus;
 import com.qmth.teachcloud.mark.entity.MarkGroupStudent;
 import com.baomidou.mybatisplus.extension.service.IService;
 
@@ -13,4 +14,5 @@ import com.baomidou.mybatisplus.extension.service.IService;
  */
 public interface MarkGroupStudentService extends IService<MarkGroupStudent> {
 
+    long countByStudentIdAndStatus(Long studentId, SubjectiveStatus marked);
 }

+ 4 - 1
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/MarkHeaderTrackService.java

@@ -1,7 +1,7 @@
 package com.qmth.teachcloud.mark.service;
 
-import com.qmth.teachcloud.mark.entity.MarkHeaderTrack;
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.qmth.teachcloud.mark.entity.MarkHeaderTrack;
 
 import java.util.List;
 
@@ -16,4 +16,7 @@ import java.util.List;
 public interface MarkHeaderTrackService extends IService<MarkHeaderTrack> {
 
     List<MarkHeaderTrack> listByExamAndPaperNumberAndGroupNumberAndStudentId(Long examId, String paperNumber, Integer groupNumber, Long studentId);
+
+    void deleteByExamIdAndPaperNumberAndGroupNumberAndStudentId(Long examId, String paperNumber, Integer groupNumber, Long studentId);
+
 }

+ 2 - 0
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/MarkQuestionService.java

@@ -40,4 +40,6 @@ public interface MarkQuestionService extends IService<MarkQuestion> {
     String previewAnswerFileByExamIdAndPaperNumber(Long examId, String paperNumber);
 
     double sumTotalScoreByGroupNumber(Long examId, String paperNumber, Integer groupNumber);
+
+    long countQuestionByExamIdAndPaperNumberAndGroupNumberIsNull(Long examId, String paperNumber, boolean isObjective);
 }

+ 5 - 0
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/MarkService.java

@@ -3,6 +3,7 @@ package com.qmth.teachcloud.mark.service;
 import com.qmth.teachcloud.mark.entity.MarkGroup;
 import com.qmth.teachcloud.mark.entity.MarkTask;
 import com.qmth.teachcloud.mark.entity.MarkUserGroup;
+import com.qmth.teachcloud.mark.params.MarkResult;
 
 /**
  * <p>
@@ -27,4 +28,8 @@ public interface MarkService {
     void updateQuality(MarkUserGroup markUserGroup);
 
     boolean needUpdateQuality(MarkUserGroup marker, int expireMinutes);
+
+    void processArbitrate(MarkResult markResult, Long userId);
+
+    void checkStudentSubjective(Long studentId, long groupCount, long unGroupQuestionCount);
 }

+ 1 - 1
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/MarkStudentService.java

@@ -20,7 +20,7 @@ public interface MarkStudentService extends IService<MarkStudent> {
 
     List<String> listClassByExamIdAndCourseCode(Long examId, String paperNumber);
 
-    void updateSubjectiveStatusAndScore(Long studentId, SubjectiveStatus status, int score, String scoreList);
+    void updateSubjectiveStatusAndScore(Long studentId, SubjectiveStatus status, Double score, String scoreList);
 
 	ScanExamInfoVo getScanExamInfo(BasicExam exam);
 }

+ 3 - 0
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/MarkSubjectiveScoreService.java

@@ -3,6 +3,8 @@ package com.qmth.teachcloud.mark.service;
 import com.qmth.teachcloud.mark.entity.MarkSubjectiveScore;
 import com.baomidou.mybatisplus.extension.service.IService;
 
+import java.util.List;
+
 /**
  * <p>
  * 主观题得分明细表 服务类
@@ -13,4 +15,5 @@ import com.baomidou.mybatisplus.extension.service.IService;
  */
 public interface MarkSubjectiveScoreService extends IService<MarkSubjectiveScore> {
 
+    List<MarkSubjectiveScore> listByStudentIdAndGroupNumber(Long studentId, Integer groupNumber);
 }

+ 2 - 0
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/MarkTaskService.java

@@ -42,4 +42,6 @@ public interface MarkTaskService extends IService<MarkTask> {
     MarkTask getLastOneByUserIdAndStatus(Long examId, String paperNumber, Integer groupNumber, Long userId, MarkTaskStatus status);
 
     List<MarkTask> listByExamIdAndPaperNumberAndGroupNumberAndStudentId(Long examId, String paperNumber, Integer groupNumber, Long studentId);
+
+    void updateHeaderResult(Long examId, String paperNumber, Integer groupNumber, Long studentId, Long updateUserId, Double totalScore, String scoreList, Long updateTime, MarkTaskStatus arbitrated);
 }

+ 28 - 0
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkArbitrateHistoryServiceImpl.java

@@ -17,7 +17,10 @@ import com.qmth.teachcloud.mark.entity.MarkArbitrateHistory;
 import com.qmth.teachcloud.mark.entity.MarkGroup;
 import com.qmth.teachcloud.mark.entity.MarkTask;
 import com.qmth.teachcloud.mark.entity.MarkUserGroup;
+import com.qmth.teachcloud.mark.enums.LockType;
+import com.qmth.teachcloud.mark.lock.LockService;
 import com.qmth.teachcloud.mark.mapper.MarkArbitrateHistoryMapper;
+import com.qmth.teachcloud.mark.params.MarkResult;
 import com.qmth.teachcloud.mark.service.*;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.stereotype.Service;
@@ -57,6 +60,10 @@ public class MarkArbitrateHistoryServiceImpl extends ServiceImpl<MarkArbitrateHi
     private TaskService taskService;
     @Resource
     private TeachcloudCommonService teachcloudCommonService;
+    @Resource
+    private MarkService markService;
+    @Resource
+    private LockService lockService;
 
     @Override
     public IPage<MarkArbitrateDto> pageArbitrate(Long examId, String paperNumber, Integer groupNumber, Integer pageNumber, Integer pageSize) {
@@ -143,6 +150,27 @@ public class MarkArbitrateHistoryServiceImpl extends ServiceImpl<MarkArbitrateHi
         return taskService.build(markArbitrateHistory, markGroup);
     }
 
+    @Override
+    public void saveArbitrateTask(MarkResult markResult) {
+        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
+        MarkArbitrateHistory markArbitrateHistory = this.getById(markResult.getLibraryId());
+        if (markArbitrateHistory != null) {
+            try {
+                lockService.watch(LockType.EXAM_SUBJECT, markArbitrateHistory.getExamId(), markArbitrateHistory.getPaperNumber());
+                lockService.watch(LockType.GROUP, markArbitrateHistory.getExamId(), markArbitrateHistory.getPaperNumber(), markArbitrateHistory.getGroupNumber());
+                markService.processArbitrate(markResult, sysUser.getId());
+                releaseTask(markArbitrateHistory.getId());
+            } catch (Exception e) {
+                log.error("ArbitrateController-处理仲裁卷出错", e);
+            } finally {
+                lockService.unwatch(LockType.GROUP, markArbitrateHistory.getExamId(), markArbitrateHistory.getPaperNumber(), markArbitrateHistory.getGroupNumber());
+                lockService.unwatch(LockType.EXAM_SUBJECT, markArbitrateHistory.getExamId(), markArbitrateHistory.getPaperNumber());
+            }
+        } else {
+            throw ExceptionResultEnum.ERROR.exception("任务不存在");
+        }
+    }
+
     private void releaseTask(Long taskId) {
         synchronized (currentTaskMap) {
             currentTaskMap.remove(taskId);

+ 1 - 1
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkGroupServiceImpl.java

@@ -75,7 +75,7 @@ public class MarkGroupServiceImpl extends ServiceImpl<MarkGroupMapper, MarkGroup
                 markGroupDto.setGroupNumber(markGroup.getNumber());
                 markGroupDto.setDoubleRate(markGroup.getDoubleRate());
                 markGroupDto.setArbitrateThreshold(markGroup.getArbitrateThreshold());
-                markGroupDto.setScorePolicy(markGroup.getScorePolicy());
+                markGroupDto.setScorePolicy(markGroup.getScorePolicy().name());
                 if (StringUtils.isNotBlank(markGroup.getPicList())) {
                     markGroupDto.setPictureConfigs(JSON.parseArray(markGroup.getPicList(), PictureConfig.class));
                 }

+ 10 - 1
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkGroupStudentServiceImpl.java

@@ -1,9 +1,11 @@
 package com.qmth.teachcloud.mark.service.impl;
 
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.qmth.teachcloud.common.enums.mark.SubjectiveStatus;
 import com.qmth.teachcloud.mark.entity.MarkGroupStudent;
 import com.qmth.teachcloud.mark.mapper.MarkGroupStudentMapper;
 import com.qmth.teachcloud.mark.service.MarkGroupStudentService;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import org.springframework.stereotype.Service;
 
 /**
@@ -17,4 +19,11 @@ import org.springframework.stereotype.Service;
 @Service
 public class MarkGroupStudentServiceImpl extends ServiceImpl<MarkGroupStudentMapper, MarkGroupStudent> implements MarkGroupStudentService {
 
+    @Override
+    public long countByStudentIdAndStatus(Long studentId, SubjectiveStatus marked) {
+        QueryWrapper<MarkGroupStudent> queryWrapper = new QueryWrapper<>();
+        queryWrapper.lambda().eq(MarkGroupStudent::getStudentId, studentId)
+                .eq(MarkGroupStudent::getStatus, marked);
+        return this.count(queryWrapper);
+    }
 }

+ 12 - 0
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkHeaderTrackServiceImpl.java

@@ -1,6 +1,7 @@
 package com.qmth.teachcloud.mark.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.qmth.teachcloud.mark.entity.MarkHeaderTrack;
 import com.qmth.teachcloud.mark.mapper.MarkHeaderTrackMapper;
@@ -29,4 +30,15 @@ public class MarkHeaderTrackServiceImpl extends ServiceImpl<MarkHeaderTrackMappe
                 .eq(MarkHeaderTrack::getStudentId, studentId);
         return this.list(queryWrapper);
     }
+
+    @Override
+    public void deleteByExamIdAndPaperNumberAndGroupNumberAndStudentId(Long examId, String paperNumber, Integer groupNumber, Long studentId) {
+        UpdateWrapper<MarkHeaderTrack> updateWrapper = new UpdateWrapper<>();
+        updateWrapper.lambda().eq(MarkHeaderTrack::getExamId, examId)
+                .eq(MarkHeaderTrack::getPaperNumber, paperNumber)
+                .eq(MarkHeaderTrack::getGroupNumber, groupNumber)
+                .eq(MarkHeaderTrack::getStudentId, studentId);
+        this.remove(updateWrapper);
+    }
+
 }

+ 10 - 0
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkQuestionServiceImpl.java

@@ -184,4 +184,14 @@ public class MarkQuestionServiceImpl extends ServiceImpl<MarkQuestionMapper, Mar
         Double score = this.baseMapper.sumTotalScoreByGroupNumber(examId, paperNumber, groupNumber);
         return score != null ? score.doubleValue() : 0d;
     }
+
+    @Override
+    public long countQuestionByExamIdAndPaperNumberAndGroupNumberIsNull(Long examId, String paperNumber, boolean isObjective) {
+        QueryWrapper<MarkQuestion> queryWrapper = new QueryWrapper<>();
+        queryWrapper.lambda().eq(MarkQuestion::getExamId, examId)
+                .eq(MarkQuestion::getPaperNumber, paperNumber)
+                .eq(MarkQuestion::getObjective, isObjective)
+                .isNull(MarkQuestion::getGroupNumber);
+        return this.count(queryWrapper);
+    }
 }

+ 246 - 12
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkServiceImpl.java

@@ -1,27 +1,26 @@
 package com.qmth.teachcloud.mark.service.impl;
 
-import com.qmth.teachcloud.mark.entity.MarkPaper;
+import com.qmth.teachcloud.common.enums.mark.MarkArbitrateStatus;
 import com.qmth.teachcloud.common.enums.mark.MarkPaperStatus;
 import com.qmth.teachcloud.common.enums.mark.MarkProblemStatus;
 import com.qmth.teachcloud.common.enums.mark.SubjectiveStatus;
-import com.qmth.teachcloud.mark.service.MarkPaperService;
-import com.qmth.teachcloud.mark.service.MarkStudentService;
-import com.qmth.teachcloud.mark.entity.MarkGroup;
-import com.qmth.teachcloud.mark.entity.MarkGroupStudent;
-import com.qmth.teachcloud.mark.entity.MarkTask;
-import com.qmth.teachcloud.mark.entity.MarkUserGroup;
+import com.qmth.teachcloud.mark.dto.mark.ScoreItem;
+import com.qmth.teachcloud.mark.entity.*;
 import com.qmth.teachcloud.mark.enums.LockType;
 import com.qmth.teachcloud.mark.enums.MarkTaskStatus;
+import com.qmth.teachcloud.mark.enums.ScorePolicy;
 import com.qmth.teachcloud.mark.lock.LockService;
+import com.qmth.teachcloud.mark.params.MarkResult;
 import com.qmth.teachcloud.mark.service.*;
+import com.qmth.teachcloud.mark.utils.BigDecimalUtils;
 import com.qmth.teachcloud.mark.utils.TaskLock;
 import com.qmth.teachcloud.mark.utils.TaskLockUtil;
+import org.apache.commons.collections4.CollectionUtils;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
+import java.math.BigDecimal;
+import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
 
 @Service
@@ -34,6 +33,8 @@ public class MarkServiceImpl implements MarkService {
     @Resource
     private MarkPaperService markPaperService;
     @Resource
+    private MarkQuestionService markQuestionService;
+    @Resource
     private MarkGroupService markGroupService;
     @Resource
     private MarkUserGroupService markUserGroupService;
@@ -48,6 +49,12 @@ public class MarkServiceImpl implements MarkService {
     @Resource
     private MarkProblemHistoryService markProblemHistoryService;
     @Resource
+    private MarkArbitrateHistoryService markArbitrateHistoryService;
+    @Resource
+    private MarkSubjectiveScoreService markSubjectiveScoreService;
+    @Resource
+    private MarkHeaderTrackService markHeaderTrackService;
+    @Resource
     LockService lockService;
 
     /**
@@ -116,7 +123,7 @@ public class MarkServiceImpl implements MarkService {
                 markTaskService.resetById(markTask.getId(), null, null, null, MarkTaskStatus.WAITING);
                 lockService.waitlock(LockType.STUDENT, markTask.getStudentId());
                 updateStudentGroupStatus(studentId, examId, paperNumber, groupNumber, SubjectiveStatus.UNMARK);
-                markStudentService.updateSubjectiveStatusAndScore(studentId, SubjectiveStatus.UNMARK, 0, null);
+                markStudentService.updateSubjectiveStatusAndScore(studentId, SubjectiveStatus.UNMARK, 0D, null);
 //                inspectedService.cancelByStudent(library.getStudentId());
                 lockService.unlock(LockType.STUDENT, markTask.getStudentId());
             }
@@ -154,7 +161,7 @@ public class MarkServiceImpl implements MarkService {
 
     private void resetStudentGroup(Long studentId, Long examId, String paperNumber, Integer groupNumber) {
         updateStudentGroupStatus(studentId, examId, paperNumber, groupNumber, SubjectiveStatus.UNMARK);
-        markStudentService.updateSubjectiveStatusAndScore(studentId, SubjectiveStatus.UNMARK, 0, null);
+        markStudentService.updateSubjectiveStatusAndScore(studentId, SubjectiveStatus.UNMARK, 0D, null);
     }
 
     private void updateStudentGroupStatus(Long studentId, Long examId, String paperNumber, Integer groupNumber, SubjectiveStatus status) {
@@ -223,7 +230,234 @@ public class MarkServiceImpl implements MarkService {
         return false;
     }
 
+    /**
+     * 管理员/组长处理仲裁卷
+     *
+     * @param markResult
+     * @param userId
+     */
+    @Override
+    public void processArbitrate(MarkResult markResult, Long userId) {
+        MarkArbitrateHistory markArbitrateHistory = markArbitrateHistoryService.getById(markResult.getLibraryId());
+        markArbitrateHistory.setUpdateUserId(userId);
+        markArbitrateHistory.setTotalScore(markResult.isUnselective() ? UN_SELECTIVE_SCORE : markResult.getMarkerScore());
+        markArbitrateHistory.setScoreList(markResult.isUnselective() ? null : markResult.getScoreList());
+        markArbitrateHistory.setStatus(MarkArbitrateStatus.MARKED);
+        markArbitrateHistory.setUpdateTime(System.currentTimeMillis());
+        // 保存阅卷轨迹
+        int unansweredCount = 0;
+        if (markResult.getTrackList() != null && !markResult.isUnselective()) {
+            markHeaderTrackService.deleteByExamIdAndPaperNumberAndGroupNumberAndStudentId(markArbitrateHistory.getExamId(), markArbitrateHistory.getPaperNumber(), markArbitrateHistory.getGroupNumber(), markArbitrateHistory.getStudentId());
+            List<MarkHeaderTrack> tracks = markResult.getTrackList(markArbitrateHistory);
+            for (MarkHeaderTrack t : tracks) {
+                markHeaderTrackService.saveOrUpdate(t);
+            }
+        }
+        // 保存特殊标记
+//        if (result.getSpecialTagList() != null && !result.isUnselective()) {
+//            headerTagDao.deleteByStudentIdAndGroupNumber(history.getStudentId(), history.getGroupNumber());
+//            headerTagDao.save(result.getHeaderTagList(history));
+//        }
+        markArbitrateHistoryService.saveOrUpdate(markArbitrateHistory);
+        markTaskService.updateHeaderResult(markArbitrateHistory.getExamId(), markArbitrateHistory.getPaperNumber(), markArbitrateHistory.getGroupNumber(), markArbitrateHistory.getStudentId(), markArbitrateHistory.getUpdateUserId(), markArbitrateHistory.getTotalScore(), markArbitrateHistory.getScoreList(), markArbitrateHistory.getUpdateTime(), MarkTaskStatus.ARBITRATED);
+        updateMarkedCount(markArbitrateHistory.getExamId(), markArbitrateHistory.getPaperNumber(), markArbitrateHistory.getGroupNumber());
+        checkStudentGroup(markArbitrateHistory.getStudentId(), markGroupService.getByExamIdAndPaperNumberAndGroupNumber(markArbitrateHistory.getExamId(), markArbitrateHistory.getPaperNumber(), markArbitrateHistory.getGroupNumber()));
+    }
+
     private String getGroupKey(MarkUserGroup markUserGroup) {
         return markUserGroup.getExamId() + "_" + markUserGroup.getPaperNumber() + "_" + markUserGroup.getGroupNumber();
     }
+
+    /**
+     * 考生分组判断是否评卷完成,以及后续的统一处理动作
+     *
+     * @param studentId
+     * @param group
+     */
+    private void checkStudentGroup(Long studentId, MarkGroup group) {
+        if (calculateGroup(group, studentId)) {
+            updateStudentGroupStatus(studentId, group.getExamId(), group.getPaperNumber(), group.getNumber(), SubjectiveStatus.MARKED);
+            updateStudentGroupScore(studentId, group.getExamId(), group.getPaperNumber(), group, group.getMarkScore(), group.getMarkScoreDetail());
+            // 未分组的题目
+            long unGroupQuestionCount = markQuestionService.countQuestionByExamIdAndPaperNumberAndGroupNumberIsNull(group.getExamId(), group.getPaperNumber(), false);
+            long groupCount = CollectionUtils.size(markGroupService.listGroupByExamIdAndPaperNumber(group.getExamId(), group.getPaperNumber()));
+            checkStudentSubjective(studentId, groupCount, unGroupQuestionCount);
+        } else {
+            updateStudentGroupStatus(studentId, group.getExamId(), group.getPaperNumber(), group.getNumber(), SubjectiveStatus.UNMARK);
+            markStudentService.updateSubjectiveStatusAndScore(studentId, SubjectiveStatus.UNMARK, 0D, null);
+        }
+    }
+
+    @Override
+    public void checkStudentSubjective(Long studentId, long groupCount, long unGroupQuestionCount) {
+        if (markGroupStudentService.countByStudentIdAndStatus(studentId, SubjectiveStatus.MARKED) == groupCount && unGroupQuestionCount == 0) {
+            scoreCalculate(studentId);
+        } else {
+            markStudentService.updateSubjectiveStatusAndScore(studentId, SubjectiveStatus.UNMARK, 0D, null);
+        }
+    }
+
+    private boolean calculateGroup(MarkGroup group, Long studentId) {
+        double score = 0;
+        List<ScoreItem> detail = new ArrayList<>();
+        int count = 0;
+        // 未设置算分策略的情况下,默认取平均分
+        ScorePolicy policy = group.getScorePolicy() != null ? group.getScorePolicy() : ScorePolicy.AVG;
+        List<MarkTask> list = markTaskService.listByExamIdAndPaperNumberAndGroupNumberAndStudentId(group.getExamId(), group.getPaperNumber(), group.getNumber(), studentId);
+        if (list.isEmpty()) {
+            return false;
+        }
+        boolean selectiveAll = false;
+        for (MarkTask markTask : list) {
+            if (markTask.getStatus() != MarkTaskStatus.MARKED && markTask.getStatus() != MarkTaskStatus.ARBITRATED) {
+                // 有非完成状态的评卷任务,直接返回
+                return false;
+            }
+            double markerScore = markTask.getStatus() == MarkTaskStatus.ARBITRATED ? markTask.getHeaderScore() : markTask.getMarkerScore();
+            if (markerScore == UN_SELECTIVE_SCORE) {
+                selectiveAll = true;
+            }
+        }
+        if (selectiveAll) {
+            group.setMarkScore(UN_SELECTIVE_SCORE);
+            return true;
+        }
+        for (MarkTask markTask : list) {
+            count++;
+            Double current = markTask.getHeaderScore() != null ? markTask.getHeaderScore() : markTask.getMarkerScore();
+            List<ScoreItem> scores = markTask.getScoreList();
+            if (count == 1) {
+                // 首份评卷任务,直接取总分与明细
+                score = current;
+                detail = scores;
+            } else {
+                switch (policy) {
+                    case AVG:
+                        // 直接累加
+                        score = BigDecimalUtils.add(score, current);
+                        for (int i = 0; i < detail.size(); i++) {
+                            try {
+                                ScoreItem item = detail.get(i);
+                                ScoreItem other = scores.get(i);
+                                item.setScore(BigDecimalUtils.add(item.getScore(), other.getScore()));
+                            } catch (Exception e) {
+                                continue;
+                            }
+                        }
+                        break;
+                    case MAX:
+                        // 高分优先
+                        if (current > score) {
+                            score = current;
+                            detail = scores;
+                        }
+                        break;
+                    case MIN:
+                        // 低分优先
+                        if (current < score) {
+                            score = current;
+                            detail = scores;
+                        }
+                        break;
+                    default:
+                        break;
+                }
+            }
+        }
+        // 取平均分策略下,累计分数需要重新计算一次
+        if (policy == ScorePolicy.AVG && count > 1) {
+            score = BigDecimalUtils.div(score, count);
+            for (ScoreItem item : detail) {
+                item.setScore(BigDecimalUtils.div(item.getScore(), count));
+            }
+        }
+        group.setMarkScore(score);
+        group.setMarkScoreDetail(detail);
+        return true;
+    }
+
+    private void updateStudentGroupScore(Long studentId, Long examId, String paperNumber, MarkGroup group, double score, List<ScoreItem> scoreList) {
+        // scoreDao.deleteByStudentIdAndGroupNumber(studentId, groupNumber);
+        List<MarkQuestion> questions = markQuestionService.listQuestionByExamIdAndPaperNumberAndGroupNumber(examId, paperNumber, group.getNumber(), false);
+        List<MarkSubjectiveScore> subjectiveScores = markSubjectiveScoreService.listByStudentIdAndGroupNumber(studentId, group.getNumber());
+        for (int i = 0; i < questions.size(); i++) {
+            MarkQuestion question = questions.get(i);
+            MarkSubjectiveScore ss;
+            if (!subjectiveScores.isEmpty() && subjectiveScores.size() == questions.size()) {
+                ss = subjectiveScores.get(i);
+            } else {
+                ss = new MarkSubjectiveScore();
+            }
+            ss.setStudentId(studentId);
+            ss.setExamId(examId);
+            ss.setPaperNumber(paperNumber);
+            ss.setGroupNumber(group.getNumber());
+            ss.setGroupScore(score);
+            ss.setMainNumber(question.getMainNumber());
+            ss.setSubNumber(String.valueOf(question.getSubNumber()));
+            if (score != UN_SELECTIVE_SCORE) {
+                ScoreItem item = scoreList.get(i);
+                ss.setScore(item.getScore());
+                ss.setMainScore(0.0);
+                ss.setUncalculate(false);
+            } else {
+                ss.setScore(score);
+                ss.setMainScore(score);
+                ss.setUncalculate(true);
+            }
+//            if (group.getArbitrateThreshold() != null && group.getArbitrateThreshold() > 0) {
+//                ss.setUnansweredCount(markHeaderTrackService.countByStudentIdAndQuestionNumberAndUnanswered(studentId, question.getQuestionNumber(), true));
+//            } else {
+//                ss.setUnansweredCount(markTaskService.countByStudentIdAndQuestionNumberAndUnanswered(studentId, question.getQuestionNumber(), true));
+//            }
+            markSubjectiveScoreService.saveOrUpdate(ss);
+        }
+    }
+
+    private void scoreCalculate(Long studentId) {
+        List<ScoreItem> scoreList = new ArrayList<>();
+        Map<Integer, List<MarkSubjectiveScore>> mainScoreMap = new HashMap<>();
+        Map<Integer, Double> scoreMap = new HashMap<>();
+
+        // 循环所有主观得分明细
+        List<MarkSubjectiveScore> list = markSubjectiveScoreService.listByStudentIdAndGroupNumber(studentId, null);
+        list.sort(null);
+        for (MarkSubjectiveScore ss : list) {
+            List<MarkSubjectiveScore> mainScoreList = mainScoreMap.get(ss.getMainNumber());
+            if (mainScoreList == null) {
+                mainScoreList = new ArrayList<MarkSubjectiveScore>();
+            }
+            mainScoreList.add(ss);
+            mainScoreMap.put(ss.getMainNumber(), mainScoreList);
+            scoreList.add(new ScoreItem(ss));
+        }
+        // 计算大题分
+        for (Integer mainNumber : mainScoreMap.keySet()) {
+            List<MarkSubjectiveScore> mainScoreList = mainScoreMap.get(mainNumber);
+            BigDecimal mainScore = BigDecimal.ZERO;
+            for (MarkSubjectiveScore subjectiveScore : mainScoreList) {
+                if (subjectiveScore.getScore() != UN_SELECTIVE_SCORE) {
+                    mainScore = mainScore.add(BigDecimal.valueOf(subjectiveScore.getScore()));
+                    subjectiveScore.setUncalculate(false);
+                } else {
+                    mainScore = new BigDecimal(UN_SELECTIVE_SCORE);
+                    subjectiveScore.setUncalculate(true);
+                    break;
+                }
+            }
+            for (MarkSubjectiveScore subjectiveScore : mainScoreList) {
+                subjectiveScore.setMainScore(mainScore.doubleValue());
+                markSubjectiveScoreService.saveOrUpdate(subjectiveScore);
+            }
+            scoreMap.put(mainNumber, mainScore.doubleValue());
+        }
+        // 计算选做题分数
+        BigDecimal totalScore = BigDecimal.ZERO;
+        // 计算非选做题总分
+        for (Integer mainNumber : scoreMap.keySet()) {
+            totalScore = totalScore.add(BigDecimal.valueOf(scoreMap.get(mainNumber)));
+        }
+        // 全部评完,更新考生主观题得分
+        markStudentService.updateSubjectiveStatusAndScore(studentId, SubjectiveStatus.MARKED, totalScore.doubleValue(), MarkStudent.buildScoreList(scoreList));
+    }
 }

+ 1 - 1
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkStudentServiceImpl.java

@@ -53,7 +53,7 @@ public class MarkStudentServiceImpl extends ServiceImpl<MarkStudentMapper, MarkS
     }
 
     @Override
-    public void updateSubjectiveStatusAndScore(Long studentId, SubjectiveStatus status, int score, String scoreList) {
+    public void updateSubjectiveStatusAndScore(Long studentId, SubjectiveStatus status, Double score, String scoreList) {
         UpdateWrapper<MarkStudent> updateWrapper = new UpdateWrapper<>();
         updateWrapper.lambda().set(MarkStudent::getSubjectiveStatus, status)
                 .set(MarkStudent::getSubjectiveScore, score)

+ 14 - 1
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkSubjectiveScoreServiceImpl.java

@@ -1,11 +1,14 @@
 package com.qmth.teachcloud.mark.service.impl;
 
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.qmth.teachcloud.mark.entity.MarkSubjectiveScore;
 import com.qmth.teachcloud.mark.mapper.MarkSubjectiveScoreMapper;
 import com.qmth.teachcloud.mark.service.MarkSubjectiveScoreService;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import org.springframework.stereotype.Service;
 
+import java.util.List;
+
 /**
  * <p>
  * 主观题得分明细表 服务实现类
@@ -17,4 +20,14 @@ import org.springframework.stereotype.Service;
 @Service
 public class MarkSubjectiveScoreServiceImpl extends ServiceImpl<MarkSubjectiveScoreMapper, MarkSubjectiveScore> implements MarkSubjectiveScoreService {
 
+    @Override
+    public List<MarkSubjectiveScore> listByStudentIdAndGroupNumber(Long studentId, Integer groupNumber) {
+        QueryWrapper<MarkSubjectiveScore> queryWrapper = new QueryWrapper<>();
+        queryWrapper.lambda().eq(MarkSubjectiveScore::getStudentId, studentId);
+        if (groupNumber != null) {
+            queryWrapper.lambda().eq(MarkSubjectiveScore::getGroupNumber, groupNumber);
+        }
+
+        return this.list(queryWrapper);
+    }
 }

+ 18 - 3
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkTaskServiceImpl.java

@@ -5,16 +5,16 @@ import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.qmth.teachcloud.mark.dto.mark.manage.MarkManageDto;
-import com.qmth.teachcloud.mark.dto.mark.manage.MarkerInfoDto;
 import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
-import com.qmth.teachcloud.mark.service.MarkQuestionService;
 import com.qmth.teachcloud.common.util.ExcelUtil;
+import com.qmth.teachcloud.mark.dto.mark.manage.MarkManageDto;
+import com.qmth.teachcloud.mark.dto.mark.manage.MarkerInfoDto;
 import com.qmth.teachcloud.mark.entity.MarkGroup;
 import com.qmth.teachcloud.mark.entity.MarkTask;
 import com.qmth.teachcloud.mark.enums.MarkTaskStatus;
 import com.qmth.teachcloud.mark.mapper.MarkTaskMapper;
 import com.qmth.teachcloud.mark.service.MarkGroupService;
+import com.qmth.teachcloud.mark.service.MarkQuestionService;
 import com.qmth.teachcloud.mark.service.MarkTaskService;
 import org.springframework.stereotype.Service;
 import org.springframework.util.CollectionUtils;
@@ -163,4 +163,19 @@ public class MarkTaskServiceImpl extends ServiceImpl<MarkTaskMapper, MarkTask> i
                 .eq(MarkTask::getStudentId, studentId);
         return this.list(queryWrapper);
     }
+
+    @Override
+    public void updateHeaderResult(Long examId, String paperNumber, Integer groupNumber, Long studentId, Long updateUserId, Double totalScore, String scoreList, Long updateTime, MarkTaskStatus arbitrated) {
+        UpdateWrapper<MarkTask> updateWrapper = new UpdateWrapper<>();
+        updateWrapper.lambda().set(MarkTask::getHeaderId, updateUserId)
+                .set(MarkTask::getHeaderScore, totalScore)
+                .set(MarkTask::getHeaderScoreList, scoreList)
+                .set(MarkTask::getHeaderTime, updateTime)
+                .set(MarkTask::getStatus, arbitrated)
+                .eq(MarkTask::getExamId, examId)
+                .eq(MarkTask::getPaperNumber, paperNumber)
+                .eq(MarkTask::getGroupNumber, groupNumber)
+                .eq(MarkTask::getStudentId, studentId);
+        this.update(updateWrapper);
+    }
 }

+ 149 - 0
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/utils/BigDecimalUtils.java

@@ -0,0 +1,149 @@
+package com.qmth.teachcloud.mark.utils;
+
+import java.math.BigDecimal;
+
+public class BigDecimalUtils {
+
+    // 榛樿闄ゆ硶杩愮畻绮惧害
+    private static final int DEF_DIV_SCALE = 10;
+
+    private BigDecimalUtils() {
+
+    }
+
+    /**
+     * 提供精确加法计算的add方法
+     *
+     * @param v1 被加数
+     * @param v2 加数
+     * @return 两个参数的和
+     */
+
+    public static double add(double v1, double v2) {
+
+        BigDecimal b1 = new BigDecimal(Double.toString(v1));
+
+        BigDecimal b2 = new BigDecimal(Double.toString(v2));
+
+        return b1.add(b2).doubleValue();
+
+    }
+
+    /**
+     * 提供精确减法运算的sub方法
+     *
+     * @param v1 被减数
+     * @param v2 减数
+     * @return 两个参数的差
+     */
+    public static double sub(double v1, double v2) {
+
+        BigDecimal b1 = new BigDecimal(Double.toString(v1));
+
+        BigDecimal b2 = new BigDecimal(Double.toString(v2));
+
+        return b1.subtract(b2).doubleValue();
+
+    }
+
+    /**
+     * 提供精确乘法运算的mul方法
+     *
+     * @param v1 被乘数
+     * @param v2 乘数
+     * @return 两个参数的积
+     */
+    public static double mul(double v1, double v2) {
+
+        BigDecimal b1 = new BigDecimal(Double.toString(v1));
+
+        BigDecimal b2 = new BigDecimal(Double.toString(v2));
+
+        return b1.multiply(b2).doubleValue();
+
+    }
+
+    /**
+     * 鎻愪緵绮剧‘鐨勪箻娉曡繍绠椼�
+     *
+     * @param v1 琚箻鏁�
+     * @param v2 涔樻暟
+     * @return 涓や釜鍙傛暟鐨勭Н
+     */
+    public static float mul(float v1, float v2) {
+
+        BigDecimal b1 = new BigDecimal(Float.toString(v1));
+
+        BigDecimal b2 = new BigDecimal(Float.toString(v2));
+
+        return b1.multiply(b2).floatValue();
+
+    }
+
+    /**
+     * 提供精确的除法运算方法div
+     *
+     * @param v1 被除数
+     * @param v2 除数
+     * @return 两个参数的商
+     * @throws IllegalAccessException
+     */
+    public static double div(double v1, double v2) {
+
+        return div(v1, v2, DEF_DIV_SCALE);
+
+    }
+
+    /**
+     * 提供精确的除法运算方法div
+     *
+     * @param v1    被除数
+     * @param v2    除数
+     * @param scale 精确范围
+     * @return 两个参数的商
+     * @throws IllegalAccessException
+     */
+
+    public static double div(double v1, double v2, int scale) {
+
+        if (scale < 0) {
+
+            throw new IllegalArgumentException(
+
+                    "The scale must be a positive integer or zero");
+
+        }
+
+        BigDecimal b1 = new BigDecimal(Double.toString(v1));
+
+        BigDecimal b2 = new BigDecimal(Double.toString(v2));
+
+        return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
+
+    }
+
+    /**
+     * 鎻愪緵绮剧‘鐨勫皬鏁颁綅鍥涜垗浜斿叆澶勭悊銆�
+     *
+     * @param v     闇�鍥涜垗浜斿叆鐨勬暟瀛�
+     * @param scale 灏忔暟鐐瑰悗淇濈暀鍑犱綅
+     * @return 鍥涜垗浜斿叆鍚庣殑缁撴灉
+     */
+    public static double round(double v, int scale) {
+
+        if (scale < 0) {
+
+            throw new IllegalArgumentException(
+
+                    "The scale must be a positive integer or zero");
+
+        }
+
+        BigDecimal b = new BigDecimal(Double.toString(v));
+
+        BigDecimal one = new BigDecimal("1");
+
+        return b.divide(one, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
+
+    }
+}