Bladeren bron

3.4.1 评卷设置-数据包导入

xiaofei 10 maanden geleden
bovenliggende
commit
cdafc1cd2e
21 gewijzigde bestanden met toevoegingen van 501 en 28 verwijderingen
  1. 14 6
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/ClientServiceImpl.java
  2. 4 4
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/ExamCardServiceImpl.java
  3. 6 0
      distributed-print-business/src/main/resources/db/log/xf.sql
  4. 18 0
      distributed-print/src/main/java/com/qmth/distributed/print/api/mark/MarkSettingController.java
  5. 34 0
      teachcloud-common/src/main/java/com/qmth/teachcloud/common/contant/SystemConstant.java
  6. 32 0
      teachcloud-common/src/main/java/com/qmth/teachcloud/common/entity/BasicPrintConfig.java
  7. 12 0
      teachcloud-common/src/main/java/com/qmth/teachcloud/common/entity/SysTools.java
  8. 48 0
      teachcloud-common/src/main/java/com/qmth/teachcloud/common/enums/OutputFileTypeEnum.java
  9. 1 1
      teachcloud-common/src/main/java/com/qmth/teachcloud/common/service/BasicCourseService.java
  10. 1 1
      teachcloud-common/src/main/java/com/qmth/teachcloud/common/service/SysToolsService.java
  11. 2 3
      teachcloud-common/src/main/java/com/qmth/teachcloud/common/service/impl/BasicCourseServiceImpl.java
  12. 4 2
      teachcloud-common/src/main/java/com/qmth/teachcloud/common/service/impl/SysToolsServiceImpl.java
  13. 3 7
      teachcloud-common/src/main/java/com/qmth/teachcloud/common/service/impl/SysUserServiceImpl.java
  14. 41 0
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/bean/cardJson/CourseCard.java
  15. 32 0
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/bean/cardJson/Description.java
  16. 25 0
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/bean/cardJson/DescriptionCode.java
  17. 23 0
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/bean/cardJson/DescriptionCourse.java
  18. 5 0
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/MarkPaperService.java
  19. 2 0
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/MarkQuestionService.java
  20. 192 4
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkPaperServiceImpl.java
  21. 2 0
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkQuestionServiceImpl.java

+ 14 - 6
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/ClientServiceImpl.java

@@ -21,6 +21,7 @@ import com.qmth.teachcloud.common.contant.SystemConstant;
 import com.qmth.teachcloud.common.entity.*;
 import com.qmth.teachcloud.common.enums.ClassifyEnum;
 import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
+import com.qmth.teachcloud.common.enums.OutputFileTypeEnum;
 import com.qmth.teachcloud.common.enums.RoleTypeEnum;
 import com.qmth.teachcloud.common.service.*;
 import com.qmth.teachcloud.common.util.ExamTaskUtil;
@@ -46,6 +47,8 @@ public class ClientServiceImpl implements ClientService {
     @Resource
     private BasicCourseService basicCourseService;
     @Resource
+    private BasicPrintConfigService basicPrintConfigService;
+    @Resource
     private ExamTaskService examTaskService;
     @Resource
     private ExamTaskDetailService examTaskDetailService;
@@ -274,6 +277,7 @@ public class ClientServiceImpl implements ClientService {
         for (String string : strings) {
             Long examDetailId = Long.valueOf(string);
             ExamDetail examDetail = examDetailService.getById(examDetailId);
+
             // 撤回提示
             if (ExamDetailStatusEnum.NEW.equals(examDetail.getStatus()) || ExamDetailStatusEnum.READY.equals(examDetail.getStatus())) {
                 throw ExceptionResultEnum.ERROR.exception("该任务已被撤回");
@@ -292,6 +296,9 @@ public class ClientServiceImpl implements ClientService {
             ExamPrintPlan examPrintPlan = examPrintPlanService.getById(examDetail.getPrintPlanId());
             // 2.取生成的完整的pdf
             String printContent = examPrintPlan.getPrintContent();
+            BasicPrintConfig basicPrintConfig = basicPrintConfigService.getByExamId(examDetail.getExamId());
+            // 输出文件类型
+            List<OutputFileTypeEnum> outputFileTypeList = basicPrintConfig.getOutputFileTypeList();
             // 是否包含试卷、题卡
             if (StringUtils.isNotBlank(printContent)) {
                 // 试卷、题卡map
@@ -300,7 +307,7 @@ public class ClientServiceImpl implements ClientService {
                 Map<String, Object> backupMap = new HashMap<>();
                 // 备份数量
                 int backupCount = SystemConstant.calcBackupCount(examDetail.getBackupCount(), examDetail.getTotalSubjects(), 1);
-                if (printContent.contains("PAPER")) {
+                if (printContent.contains("PAPER") && outputFileTypeList.contains(OutputFileTypeEnum.PAPER)) {
                     if (examDetail.getAttachmentId() == null) {
                         throw ExceptionResultEnum.ERROR.exception("考场pdf文件未生成");
                     }
@@ -316,6 +323,7 @@ public class ClientServiceImpl implements ClientService {
                     }
 
                     finalMap.put("paperTotal", totalPathUrl);
+
                     // 取试卷
                     Map<String, Map<String, String>> map = mapCourseUrl(examDetailCourses);
                     // 生成试卷List
@@ -784,7 +792,7 @@ public class ClientServiceImpl implements ClientService {
                 String url = teachcloudCommonService.filePreview(Long.valueOf(paperInfoVo.getAttachmentId()));
                 paperList.add(new UrlMd5Dto(url, basicAttachment.getMd5()));
                 ExamCard examCard = examCardService.getById(paperInfoVo.getCardId());
-                if(StringUtils.isBlank(examCard.getBlankCardPath())){
+                if (StringUtils.isBlank(examCard.getBlankCardPath())) {
                     examCardService.createJpgImage(examCard);
                     examCardService.updateById(examCard);
                 }
@@ -804,19 +812,19 @@ public class ClientServiceImpl implements ClientService {
 
             List<String> examDetailIds = Arrays.asList(record.getExamDetailIds().split(","));
             List<ExamDetail> examDetails = examDetailService.listByIds(examDetailIds);
-            examDetails.stream().forEach(m->{
+            examDetails.stream().forEach(m -> {
                 JSONObject jsonObject = JSONObject.parseObject(m.getAttachmentPath());
                 String pathString = jsonObject.getString("path");
                 List<PrintPathVo> printPathVos = JSON.parseArray(pathString, PrintPathVo.class);
                 for (PrintPathVo printPathVo : printPathVos) {
                     String url = teachcloudCommonService.filePreviewByPathAndType(printPathVo.getPdfPath(), printPathVo.getUploadType().name(), printPathVo.getType(), false);
-                    if(ClassifyEnum.SIGN.equals(printPathVo.getPrintType())){
+                    if (ClassifyEnum.SIGN.equals(printPathVo.getPrintType())) {
                         signs.add(new UrlMd5Dto(url, printPathVo.getPdfMd5()));
                     }
-                    if(ClassifyEnum.PACKAGE.equals(printPathVo.getPrintType())){
+                    if (ClassifyEnum.PACKAGE.equals(printPathVo.getPrintType())) {
                         packages.add(new UrlMd5Dto(url, printPathVo.getPdfMd5()));
                     }
-                    if(ClassifyEnum.CHECK_IN.equals(printPathVo.getPrintType())){
+                    if (ClassifyEnum.CHECK_IN.equals(printPathVo.getPrintType())) {
                         checkIns.add(new UrlMd5Dto(url, printPathVo.getPdfMd5()));
                     }
                 }

+ 4 - 4
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/ExamCardServiceImpl.java

@@ -493,13 +493,13 @@ public class ExamCardServiceImpl extends ServiceImpl<ExamCardMapper, ExamCard> i
                     // 试卷类型不匹配跳过
                     continue;
                 }
-                String jpgAttachmentInfo = this.getOne(new QueryWrapper<ExamCard>().lambda()
-                        .eq(ExamCard::getId, paperInfoVo.getCardId())).getJpgAttachment();
-                if (StringUtils.isBlank(jpgAttachmentInfo)) {
+                ExamCard examCard = this.getOne(new QueryWrapper<ExamCard>().lambda()
+                        .eq(ExamCard::getId, paperInfoVo.getCardId()));
+                if (examCard == null || StringUtils.isBlank(examCard.getJpgAttachment())) {
                     return new ArrayList<>();
                 }
 
-                List<ConvertJpgStorage> convertJpgStorageList = JSONObject.parseArray(jpgAttachmentInfo, ConvertJpgStorage.class);
+                List<ConvertJpgStorage> convertJpgStorageList = JSONObject.parseArray(examCard.getJpgAttachment(), ConvertJpgStorage.class);
 
                 cardJpgResultList.addAll(convertJpgStorageList.stream().flatMap(e -> {
                     BasicAttachment basicAttachment = basicAttachmentService.getById(e.getAttachmentId());

+ 6 - 0
distributed-print-business/src/main/resources/db/log/xf.sql

@@ -5,3 +5,9 @@ CREATE TABLE `sys_tools` (
     `create_time` BIGINT(20) NULL,
     PRIMARY KEY (`type`))
     COMMENT = '工具管理';
+
+ALTER TABLE `basic_print_config` ADD COLUMN `output_file_type` VARCHAR(100) NULL COMMENT '输出文件类型' AFTER `print_method`;
+update basic_print_config set output_file_type = '["PAPER","ALL_CARD","PACKAGE","SIGN","CHECK_IN"]' where output_file_type is null;
+
+INSERT INTO `sys_privilege` (`id`, `name`, `url`, `type`, `parent_id`, `sequence`, `property`, `related`, `enable`, `default_auth`, `front_display`) VALUES ('1151', '导入数据包', 'CardJsonImport', 'BUTTON', '897', '9', 'AUTH', '1152', '1', '0', '1');
+INSERT INTO `sys_privilege` (`id`, `name`, `url`, `type`, `parent_id`, `sequence`, `property`, `enable`, `default_auth`, `front_display`) VALUES ('1152', '导入数据包', '/api/admin/mark/setting/card_json/import', 'URL', '897', '20', 'AUTH', '1', '1', '1');

+ 18 - 0
distributed-print/src/main/java/com/qmth/distributed/print/api/mark/MarkSettingController.java

@@ -3,6 +3,7 @@ package com.qmth.distributed.print.api.mark;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.qmth.boot.api.constant.ApiConstant;
 import com.qmth.distributed.print.business.entity.ExamTaskDetail;
+import com.qmth.distributed.print.business.service.BasicExamService;
 import com.qmth.distributed.print.business.service.ExamTaskDetailService;
 import com.qmth.distributed.print.business.service.PrintCommonService;
 import com.qmth.distributed.print.business.templete.execute.AsyncObjectiveStructImportService;
@@ -12,6 +13,8 @@ import com.qmth.teachcloud.common.bean.dto.mark.MarkSettingDto;
 import com.qmth.teachcloud.common.bean.params.mark.setting.MarkPaperSettingParam;
 import com.qmth.teachcloud.common.bean.vo.PaperInfoVo;
 import com.qmth.teachcloud.common.contant.SystemConstant;
+import com.qmth.teachcloud.common.entity.BasicExam;
+import com.qmth.teachcloud.common.enums.ExamModelEnum;
 import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
 import com.qmth.teachcloud.common.enums.TaskTypeEnum;
 import com.qmth.teachcloud.common.enums.log.OperationTypeEnum;
@@ -50,6 +53,8 @@ import java.util.Map;
 @RequestMapping(ApiConstant.DEFAULT_URI_PREFIX + SystemConstant.PREFIX_URL_MARK + "/setting")
 public class MarkSettingController {
 
+    @Resource
+    private BasicExamService basicExamService;
     @Resource
     private MarkPaperService markPaperService;
     @Resource
@@ -209,4 +214,17 @@ public class MarkSettingController {
         asyncSubjectiveStructImportService.importTask(map);
         return ResultUtil.success(true);
     }
+
+    @ApiOperation(value = "导入数据包")
+    @RequestMapping(value = "/card_json/import", method = RequestMethod.POST)
+    public Result cardJsonImport(@ApiParam(value = "考试ID", required = true) @RequestParam Long examId,
+                                 @ApiParam(value = "数据文件", required = true) @RequestParam MultipartFile file,
+                                 @ApiParam(value = "md5", required = true) @RequestParam String md5) {
+        BasicExam basicExam = basicExamService.getById(examId);
+        if (basicExam == null || !ExamModelEnum.MODEL4.equals(basicExam.getExamModel())) {
+            throw ExceptionResultEnum.ERROR.exception("当前考试无法使用此功能");
+        }
+        markPaperService.importCardJsonData(examId, file, md5);
+        return ResultUtil.success(true);
+    }
 }

+ 34 - 0
teachcloud-common/src/main/java/com/qmth/teachcloud/common/contant/SystemConstant.java

@@ -1300,6 +1300,40 @@ public class SystemConstant {
         return score;
     }
 
+    public static String readJson(InputStream inputStream) {
+        try {
+            // 读取目标文件的内容
+            StringBuilder content = new StringBuilder();
+            byte[] buffer = new byte[1024];
+            int length;
+            while ((length = inputStream.read(buffer)) > 0) {
+                content.append(new String(buffer, 0, length));
+            }
+            return content.toString();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * 路径拼接
+     *
+     * @param endSeparator 结尾是否带分隔符
+     * @param paths        路径数组
+     */
+    public static String buildPath(boolean endSeparator, String... paths) {
+        StringJoiner stringJoiner = new StringJoiner(File.separator);
+        for (String path : paths) {
+            stringJoiner.add(path);
+        }
+        String path = stringJoiner.toString();
+        if (endSeparator) {
+            path = path + File.separator;
+        }
+        return path;
+    }
+
 
     public static void addSummary(StringJoiner stringJoinerSummary, String message) {
         // 时间:事件

+ 32 - 0
teachcloud-common/src/main/java/com/qmth/teachcloud/common/entity/BasicPrintConfig.java

@@ -1,15 +1,23 @@
 package com.qmth.teachcloud.common.entity;
 
+import com.alibaba.fastjson.JSON;
 import com.baomidou.mybatisplus.annotation.TableField;
 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.common.base.BaseEntity;
 import com.qmth.teachcloud.common.enums.DrawRuleEnum;
+import com.qmth.teachcloud.common.enums.OutputFileTypeEnum;
 import com.qmth.teachcloud.common.enums.PrintMethodEnum;
 import io.swagger.annotations.ApiModelProperty;
+import jodd.util.ArraysUtil;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.StringUtils;
 
 import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 
 /**
  * <p>
@@ -103,6 +111,15 @@ public class BasicPrintConfig extends BaseEntity implements Serializable {
     @TableField("ordinary_content")
     private String ordinaryContent;
 
+    /**
+     * 输出文件类型
+     */
+    @TableField("output_file_type")
+    private String outputFileType;
+
+    @TableField(exist = false)
+    private List<OutputFileTypeEnum> outputFileTypeList;
+
     public Long getSchoolId() {
         return schoolId;
     }
@@ -215,4 +232,19 @@ public class BasicPrintConfig extends BaseEntity implements Serializable {
         this.ordinaryContent = ordinaryContent;
     }
 
+    public String getOutputFileType() {
+        return outputFileType;
+    }
+
+    public void setOutputFileType(String outputFileType) {
+        this.outputFileType = outputFileType;
+    }
+
+    public List<OutputFileTypeEnum> getOutputFileTypeList() {
+        return StringUtils.isNotBlank(this.outputFileType) ? JSON.parseArray(this.outputFileType, OutputFileTypeEnum.class) : new ArrayList<>();
+    }
+
+    public void setOutputFileTypeList(List<OutputFileTypeEnum> outputFileTypeList) {
+        this.outputFileTypeList = outputFileTypeList;
+    }
 }

+ 12 - 0
teachcloud-common/src/main/java/com/qmth/teachcloud/common/entity/SysTools.java

@@ -1,5 +1,6 @@
 package com.qmth.teachcloud.common.entity;
 
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.TableId;
@@ -34,6 +35,9 @@ public class SysTools implements Serializable {
 
     private Long createTime;
 
+    @TableField(exist = false)
+    private String url;
+
     public SysTools() {
     }
 
@@ -71,6 +75,14 @@ public class SysTools implements Serializable {
         this.createTime = createTime;
     }
 
+    public String getUrl() {
+        return url;
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
     @Override
     public String toString() {
         return "SysTools{" +

+ 48 - 0
teachcloud-common/src/main/java/com/qmth/teachcloud/common/enums/OutputFileTypeEnum.java

@@ -0,0 +1,48 @@
+package com.qmth.teachcloud.common.enums;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 输出文件类型
+ */
+public enum OutputFileTypeEnum {
+
+    PAPER("试卷文件", "试卷"),
+    ALL_CARD("全部题卡", "全部题卡"),
+    CUSTOM_CARD("仅专卡", "仅专卡"),
+    PACKAGE("卷袋贴文件", "卷袋贴"),
+    SIGN("签到表文件", "签到表"),
+    CHECK_IN("登记表文件", "考试情况登记表");
+
+    OutputFileTypeEnum(String desc, String title) {
+        this.desc = desc;
+        this.title = title;
+    }
+
+    private String desc;
+
+    private String title;
+
+    public String getDesc() {
+        return desc;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public static List<EnumResult> listTypes() {
+        List<EnumResult> list = new ArrayList<EnumResult>();
+        for (OutputFileTypeEnum value : OutputFileTypeEnum.values()) {
+            EnumResult result = new EnumResult();
+            result.setName(value.name());
+            result.setOrdinal(value.ordinal());
+            result.setCode(null);
+            result.setDesc(value.getDesc());
+            list.add(result);
+        }
+        return list;
+    }
+
+}

+ 1 - 1
teachcloud-common/src/main/java/com/qmth/teachcloud/common/service/BasicCourseService.java

@@ -89,7 +89,7 @@ public interface BasicCourseService extends IService<BasicCourse> {
      */
     List<TeachCourseSelectResult> listByOrgId(Long orgId, Long examId, String courseName, SysUser requestUser);
 
-    BasicCourse getByCode(String courseCode);
+    List<BasicCourse> listBySchoolIdAndCode(Long schoolId, String courseCode);
 
     void importBasicCourse(MultipartFile file);
 

+ 1 - 1
teachcloud-common/src/main/java/com/qmth/teachcloud/common/service/SysToolsService.java

@@ -17,5 +17,5 @@ public interface SysToolsService extends IService<SysTools> {
 
     void upload(MultipartFile file, String md5, ToolsTypeEnum type);
 
-    String getExternalByType(ToolsTypeEnum type);
+    SysTools getExternalByType(ToolsTypeEnum type);
 }

+ 2 - 3
teachcloud-common/src/main/java/com/qmth/teachcloud/common/service/impl/BasicCourseServiceImpl.java

@@ -258,12 +258,11 @@ public class BasicCourseServiceImpl extends ServiceImpl<BasicCourseMapper, Basic
     }
 
     @Override
-    public BasicCourse getByCode(String courseCode) {
-        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
+    public List<BasicCourse> listBySchoolIdAndCode(Long schoolId, String courseCode) {
         QueryWrapper<BasicCourse> queryWrapper = new QueryWrapper<>();
         queryWrapper.lambda().eq(BasicCourse::getSchoolId, schoolId)
                 .eq(BasicCourse::getCode, courseCode);
-        return this.getOne(queryWrapper);
+        return this.list(queryWrapper);
     }
 
 

+ 4 - 2
teachcloud-common/src/main/java/com/qmth/teachcloud/common/service/impl/SysToolsServiceImpl.java

@@ -70,10 +70,12 @@ public class SysToolsServiceImpl extends ServiceImpl<SysToolsMapper, SysTools> i
     }
 
     @Override
-    public String getExternalByType(ToolsTypeEnum type) {
+    public SysTools getExternalByType(ToolsTypeEnum type) {
         SysTools sysTools = this.getById(type);
         if (sysTools != null) {
-            return fileUploadService.filePreview(sysTools.getPath());
+            sysTools.setUrl(fileUploadService.filePreview(sysTools.getPath()));
+            sysTools.setPath(null);
+            return sysTools;
         }
         return null;
     }

+ 3 - 7
teachcloud-common/src/main/java/com/qmth/teachcloud/common/service/impl/SysUserServiceImpl.java

@@ -210,17 +210,13 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
         if (sysUser == null) {
             throw ExceptionResultEnum.ERROR.exception("用户不存在");
         }
-        if (!StringUtils.equals(sysUser.getPassword(), user.getOldPassword())) {
-            throw ExceptionResultEnum.ERROR.exception("原密码不正确");
-        }
         String newPwd = user.getPassword();
         String mobileNumber = user.getMobileNumber();
         String verifyCode = user.getVerifyCode();
-        String oldPassword = user.getOldPassword();
         if (SystemConstant.strNotNull(newPwd)) {
-            // 参数中存在密码 -》 更新密码
-            if (SystemConstant.strNotNull(oldPassword) && oldPassword.equals(newPwd)) {
-                throw ExceptionResultEnum.ERROR.exception("新密码和旧密码一致请重新输入");
+            // 参数中存在密码->更新密码
+            if (sysUser.getPassword().equals(newPwd)) {
+                throw ExceptionResultEnum.ERROR.exception("新密码和旧密码一致请重新输入");
             }
             sysUser.setPwdCount(sysUser.getPwdCount() == null ? 1 : sysUser.getPwdCount() + 1);
             sysUser.setPwdUpdateTime(System.currentTimeMillis());

+ 41 - 0
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/bean/cardJson/CourseCard.java

@@ -0,0 +1,41 @@
+package com.qmth.teachcloud.mark.bean.cardJson;
+
+public class CourseCard {
+
+    private String code;
+    private String courseCode;
+    private String courseName;
+
+    public CourseCard() {
+    }
+
+    public CourseCard(String code, String courseCode, String courseName) {
+        this.code = code;
+        this.courseCode = courseCode;
+        this.courseName = courseName;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    public String getCourseCode() {
+        return courseCode;
+    }
+
+    public void setCourseCode(String courseCode) {
+        this.courseCode = courseCode;
+    }
+
+    public String getCourseName() {
+        return courseName;
+    }
+
+    public void setCourseName(String courseName) {
+        this.courseName = courseName;
+    }
+}

+ 32 - 0
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/bean/cardJson/Description.java

@@ -0,0 +1,32 @@
+package com.qmth.teachcloud.mark.bean.cardJson;
+
+import org.apache.commons.collections4.CollectionUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Description {
+
+    private List<DescriptionCode> list;
+
+    public List<DescriptionCode> getList() {
+        return list;
+    }
+
+    public void setList(List<DescriptionCode> list) {
+        this.list = list;
+    }
+
+    public List<CourseCard> getCourseCardList() {
+        List<CourseCard> courseCardList = new ArrayList<>();
+        if (CollectionUtils.isNotEmpty(list)) {
+            for (DescriptionCode descriptionCode : list) {
+                for (DescriptionCourse course : descriptionCode.getCourses()) {
+                    courseCardList.add(new CourseCard(descriptionCode.getCode(), course.getCode(), course.getName()));
+                }
+            }
+        }
+        return courseCardList;
+    }
+
+}

+ 25 - 0
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/bean/cardJson/DescriptionCode.java

@@ -0,0 +1,25 @@
+package com.qmth.teachcloud.mark.bean.cardJson;
+
+import java.util.List;
+
+public class DescriptionCode {
+
+    private String code;
+    private List<DescriptionCourse> courses;
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    public List<DescriptionCourse> getCourses() {
+        return courses;
+    }
+
+    public void setCourses(List<DescriptionCourse> courses) {
+        this.courses = courses;
+    }
+}

+ 23 - 0
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/bean/cardJson/DescriptionCourse.java

@@ -0,0 +1,23 @@
+package com.qmth.teachcloud.mark.bean.cardJson;
+
+public class DescriptionCourse {
+
+    private String code;
+    private String name;
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+}

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

@@ -15,6 +15,7 @@ import com.qmth.teachcloud.mark.dto.mark.score.CheckScoreListDto;
 import com.qmth.teachcloud.mark.dto.mark.score.MarkPaperPackageDto;
 import com.qmth.teachcloud.mark.dto.mark.score.SettingDto;
 import com.qmth.teachcloud.mark.entity.MarkPaper;
+import org.springframework.web.multipart.MultipartFile;
 
 import java.util.List;
 
@@ -93,4 +94,8 @@ public interface MarkPaperService extends IService<MarkPaper> {
      * @return List<MarkPaper>
      */
     List<MarkPaper> findMarkPaperListByExamId(Long examId);
+
+    void importCardJsonData(Long examId, MultipartFile file, String md5);
+
+    List<MarkPaper> listByExamIdAndCourseIdForModel4(Long examId, Long courseId);
 }

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

@@ -5,6 +5,8 @@ import java.util.List;
 import javax.servlet.http.HttpServletResponse;
 
 import com.qmth.teachcloud.common.bean.result.MarkQuestionResult;
+import com.qmth.teachcloud.mark.bean.cardJson.DescriptionCourse;
+import com.qmth.teachcloud.mark.bean.vo.parseCard.Struct;
 import org.springframework.web.multipart.MultipartFile;
 
 import com.baomidou.mybatisplus.extension.service.IService;

+ 192 - 4
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkPaperServiceImpl.java

@@ -1,5 +1,6 @@
 package com.qmth.teachcloud.mark.service.impl;
 
+import com.alibaba.fastjson.JSON;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
@@ -7,46 +8,64 @@ 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.boot.tools.io.ZipReader;
 import com.qmth.teachcloud.common.bean.dto.DataPermissionRule;
 import com.qmth.teachcloud.common.bean.dto.mark.MarkSettingDto;
 import com.qmth.teachcloud.common.bean.params.mark.setting.MarkPaperSettingConfig;
 import com.qmth.teachcloud.common.bean.params.mark.setting.MarkPaperSettingList;
 import com.qmth.teachcloud.common.bean.params.mark.setting.MarkPaperSettingParam;
+import com.qmth.teachcloud.common.bean.vo.FilePathVo;
+import com.qmth.teachcloud.common.contant.SystemConstant;
 import com.qmth.teachcloud.common.entity.BasicCourse;
 import com.qmth.teachcloud.common.entity.BasicExam;
 import com.qmth.teachcloud.common.entity.MarkQuestion;
 import com.qmth.teachcloud.common.entity.SysUser;
 import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
+import com.qmth.teachcloud.common.enums.ObjectivePolicy;
+import com.qmth.teachcloud.common.enums.UploadFileEnum;
 import com.qmth.teachcloud.common.enums.mark.MarkMode;
 import com.qmth.teachcloud.common.enums.mark.MarkPaperStatus;
 import com.qmth.teachcloud.common.enums.mark.SubjectiveStatus;
 import com.qmth.teachcloud.common.service.BasicCourseService;
 import com.qmth.teachcloud.common.service.BasicRoleDataPermissionService;
+import com.qmth.teachcloud.common.service.FileUploadService;
 import com.qmth.teachcloud.common.service.TeachcloudCommonService;
+import com.qmth.teachcloud.common.util.FileUtil;
 import com.qmth.teachcloud.common.util.ServletUtil;
 import com.qmth.teachcloud.mark.bean.archivescore.ArchiveScoreQuery;
 import com.qmth.teachcloud.mark.bean.archivescore.ArchiveScoreVo;
+import com.qmth.teachcloud.mark.bean.cardJson.CourseCard;
+import com.qmth.teachcloud.mark.bean.cardJson.Description;
+import com.qmth.teachcloud.mark.bean.cardJson.DescriptionCode;
 import com.qmth.teachcloud.mark.bean.document.ArchivePaperQuery;
 import com.qmth.teachcloud.mark.bean.document.ArchivePaperVo;
+import com.qmth.teachcloud.mark.bean.vo.parseCard.Struct;
 import com.qmth.teachcloud.mark.dto.mark.score.CheckScoreListDto;
 import com.qmth.teachcloud.mark.dto.mark.score.MarkPaperPackageDto;
 import com.qmth.teachcloud.mark.dto.mark.score.SettingDto;
 import com.qmth.teachcloud.mark.entity.MarkPaper;
 import com.qmth.teachcloud.mark.entity.MarkStudent;
+import com.qmth.teachcloud.mark.entity.ScanAnswerCard;
 import com.qmth.teachcloud.mark.entity.ScanPackage;
+import com.qmth.teachcloud.mark.enums.CardSource;
 import com.qmth.teachcloud.mark.enums.OmrTaskStatus;
 import com.qmth.teachcloud.mark.mapper.MarkPaperMapper;
 import com.qmth.teachcloud.mark.service.*;
 import com.qmth.teachcloud.mark.utils.Calculator;
+import com.qmth.teachcloud.mark.utils.CardParseUtils;
+import org.apache.commons.codec.digest.DigestUtils;
 import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.FilenameUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.multipart.MultipartFile;
 
 import javax.annotation.Resource;
-import java.util.List;
-import java.util.Objects;
-import java.util.StringJoiner;
+import java.io.File;
+import java.util.*;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 
 /**
@@ -65,6 +84,8 @@ public class MarkPaperServiceImpl extends ServiceImpl<MarkPaperMapper, MarkPaper
     @Resource
     private ScanOmrTaskService scanOmrTaskService;
     @Resource
+    private ScanAnswerCardService scanAnswerCardService;
+    @Resource
     private TeachcloudCommonService teachcloudCommonService;
     @Resource
     private BasicRoleDataPermissionService basicRoleDataPermissionService;
@@ -78,6 +99,8 @@ public class MarkPaperServiceImpl extends ServiceImpl<MarkPaperMapper, MarkPaper
     private MarkDocumentService markDocumentService;
     @Resource
     private BasicCourseService basicCourseService;
+    @Resource
+    private FileUploadService fileUploadService;
 
 
     @Override
@@ -259,7 +282,7 @@ public class MarkPaperServiceImpl extends ServiceImpl<MarkPaperMapper, MarkPaper
             this.update(updateWrapper);
         }
 
-        if(StringUtils.isNotBlank(stringJoiner.toString())){
+        if (StringUtils.isNotBlank(stringJoiner.toString())) {
             throw ExceptionResultEnum.ERROR.exception(stringJoiner.toString());
         }
 
@@ -484,4 +507,169 @@ public class MarkPaperServiceImpl extends ServiceImpl<MarkPaperMapper, MarkPaper
     public List<MarkPaper> findMarkPaperListByExamId(Long examId) {
         return this.baseMapper.findMarkPaperListByExamId(examId);
     }
+
+    @Transactional
+    @Override
+    public void importCardJsonData(Long examId, MultipartFile file, String md5) {
+        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
+        File parentDirVar = null;
+        try {
+            String fileName = FilenameUtils.getName(file.getOriginalFilename());
+
+            if (!fileName.endsWith(SystemConstant.ZIP_PREFIX)) {
+                throw ExceptionResultEnum.ERROR.exception("数据包只能上传后缀为[.zip]的文件");
+            }
+
+            String fileMd5 = DigestUtils.md5Hex(file.getBytes());
+            if (!Objects.equals(fileMd5, md5)) {
+                throw ExceptionResultEnum.MD5_EQUALS_FALSE.exception();
+            }
+
+            // 数据包文件上传
+            parentDirVar = SystemConstant.getFileTempDirVar(SystemConstant.ZIP_PREFIX);
+            FileUtils.copyToFile(file.getInputStream(), parentDirVar);
+            ZipReader zipReader = new ZipReader(parentDirVar);
+            String descriptionJson = "description.json";
+
+            // 读取指定文件内容description.json
+            String descriptionContent = SystemConstant.readJson(zipReader.read(descriptionJson));
+            if (StringUtils.isBlank(descriptionContent)) {
+                throw ExceptionResultEnum.ERROR.exception("数据包description.json文件内容为空");
+            }
+            // 解析description.json内容
+            Description description = JSON.parseObject(descriptionContent, Description.class);
+            List<CourseCard> courseCardList = description.getCourseCardList();
+            if (CollectionUtils.isEmpty(courseCardList)) {
+                throw ExceptionResultEnum.ERROR.exception("没有可导入文件");
+            }
+
+            // 相同课程代码,取第一个题卡
+            Map<String, CourseCard> courseCardMap = courseCardList.stream().collect(Collectors.toMap(m -> m.getCourseCode(), Function.identity(), (v1, v2) -> v1));
+            for (Map.Entry<String, CourseCard> entry : courseCardMap.entrySet()) {
+                String courseCode = entry.getKey();
+                CourseCard courseCard = entry.getValue();
+                String jsonFileName = courseCard.getCode() + SystemConstant.ZIP_PREFIX;
+                String jsonContent = SystemConstant.readJson(zipReader.read(jsonFileName));
+
+                // 解析试卷结构,结构为空,跳过导入
+                List<Struct> structList = CardParseUtils.parseCardContent(jsonContent);
+                if (CollectionUtils.isEmpty(structList)) {
+                    continue;
+                }
+
+                List<BasicCourse> basicCourseList = basicCourseService.listBySchoolIdAndCode(schoolId, courseCode);
+                // 课程代码不存在,跳过导入
+                if (CollectionUtils.isEmpty(basicCourseList)) {
+                    continue;
+                }
+                // 课程代码一个对应多个开课学院,报错,文档里数据全部不写入
+                else if (basicCourseList.size() > 1) {
+                    throw ExceptionResultEnum.ERROR.exception(String.format("课程[%s(%s)]存在多个开课学院", courseCard.getCourseName(), courseCard.getCourseCode()));
+                }
+                BasicCourse basicCourse = basicCourseList.get(0);
+
+                List<MarkPaper> markPaperList = this.listByExamIdAndCourseIdForModel4(examId, basicCourse.getId());
+                if (CollectionUtils.isEmpty(markPaperList)) {
+                    continue;
+                } else if (markPaperList.size() > 1) {
+                    throw ExceptionResultEnum.ERROR.exception(String.format("课程[%s(%s)]存在多个试卷", courseCard.getCourseName(), courseCard.getCourseCode()));
+                }
+                MarkPaper markPaper = markPaperList.get(0);
+
+                List<ScanAnswerCard> scanAnswerCardList = scanAnswerCardService.listByExamIdAndPaperNumber(examId, markPaper.getPaperNumber());
+                // 已创建自定义卡格式,跳过导入
+                if (scanAnswerCardList.stream().filter(m -> CardSource.CLIENT.equals(m.getSource())).count() > 1) {
+                    continue;
+                }
+                // 电子卡格式且已适配,跳过导入
+                Optional<ScanAnswerCard> optional = scanAnswerCardList.stream().filter(m -> CardSource.WEB.equals(m.getSource())).findFirst();
+                ScanAnswerCard scanAnswerCard = null;
+                if (optional.isPresent()) {
+                    scanAnswerCard = optional.get();
+                    if (StringUtils.isNotBlank(scanAnswerCard.getAdapteUri())) {
+                        continue;
+                    }
+                }
+
+                // 主观题已分组,跳过导入
+                List<MarkQuestion> markQuestionList = markQuestionService.listByExamIdAndPaperNumberAndPaperType(examId, markPaper.getPaperNumber(), markPaper.getPaperType(), false);
+                if (CollectionUtils.isNotEmpty(markQuestionList) && markQuestionList.stream().filter(m -> m.getGroupNumber() != null).count() > 1) {
+                    continue;
+                }
+
+                // 上传电子卡格式
+                String filePathName = SystemConstant.buildPath(true, UploadFileEnum.CARD.getTitle(), String.valueOf(SystemConstant.getDbUuid())) + fileName;
+                FilePathVo filePathVo = fileUploadService.uploadFile(zipReader.read(jsonFileName), UploadFileEnum.CARD, filePathName, DigestUtils.md5Hex(zipReader.read(jsonFileName)));
+                if (filePathVo != null) {
+                    // 删除试卷结构
+                    markQuestionService.deleteByExamIdAndPaperNumber(examId, markPaper.getPaperNumber());
+                    // 保存试卷结构
+                    List<MarkQuestion> markQuestions = new ArrayList<>();
+                    for (Struct struct : structList) {
+                        MarkQuestion markQuestion = new MarkQuestion();
+                        markQuestion.setId(SystemConstant.getDbUuid());
+                        markQuestion.setExamId(examId);
+                        markQuestion.setPaperNumber(markPaper.getPaperNumber());
+                        markQuestion.setPaperType(markPaper.getPaperType());
+                        markQuestion.setObjective(struct.getObjective());
+                        markQuestion.setMainNumber(struct.getMainNumber());
+                        markQuestion.setSubNumber(struct.getSubNumber());
+                        markQuestion.setMainTitle(struct.getMainTitle());
+                        markQuestion.setOptionCount(struct.getOptionCount());
+                        markQuestion.setQuestionType(struct.getType());
+                        markQuestion.setPaperIndex(struct.getPaperIndex());
+                        markQuestion.setPageIndex(struct.getPageIndex());
+                        if (StringUtils.isNotBlank(struct.getAnswer())) {
+                            // 客观题有标答时,给分策略默认为全对给分
+                            markQuestion.setAnswer(struct.getAnswer());
+                            markQuestion.setObjectivePolicy(ObjectivePolicy.NONE);
+                        }
+                        if (struct.getScore() != null) {
+                            markQuestion.setTotalScore(struct.getScore());
+                            // 间隔分(整数默认1,小数默认0.5)
+                            if (!markQuestion.getObjective()) {
+                                markQuestion.setIntervalScore(markQuestion.getTotalScore() % 1 > 0 ? 0.5 : 1);
+                            }
+                        }
+                        markQuestions.add(markQuestion);
+                    }
+                    markQuestionService.saveBatch(markQuestions);
+                    // 删除卡格式
+                    scanAnswerCardService.deleteByExamIdAndPaperNumber(examId, markPaper.getPaperNumber());
+                    // 保存
+                    scanAnswerCard = new ScanAnswerCard();
+                    scanAnswerCard.setId(SystemConstant.getDbUuid());
+                    scanAnswerCard.setExamId(examId);
+                    scanAnswerCard.setPaperNumber(markPaper.getPaperNumber());
+                    scanAnswerCard.setCoursePaperId(markPaper.getCoursePaperId());
+                    scanAnswerCard.setPaperType(markPaper.getPaperType());
+                    scanAnswerCard.setCardId(null);
+                    scanAnswerCard.setNumber(scanAnswerCardService.findMaxCardNumberByExamId(examId) + 1);
+                    scanAnswerCard.setSource(CardSource.WEB);
+                    scanAnswerCard.setUri(JSON.toJSONString(filePathVo));
+                    scanAnswerCard.setMd5(md5);
+                    scanAnswerCard.setNeedAdapte(true);
+                    scanAnswerCard.setSinglePage(false);// 默认false
+                    // 题卡张数
+                    int paperCount = CardParseUtils.calcPaperCount(jsonContent, true);
+                    scanAnswerCard.setPaperCount(paperCount);
+                    scanAnswerCardService.save(scanAnswerCard);
+                }
+            }
+        } catch (Exception e) {
+            throw ExceptionResultEnum.ERROR.exception("上传失败:" + e.getMessage());
+        } finally {
+            if (parentDirVar != null) {
+                FileUtil.deleteFile(parentDirVar);
+            }
+        }
+    }
+
+    @Override
+    public List<MarkPaper> listByExamIdAndCourseIdForModel4(Long examId, Long courseId) {
+        QueryWrapper<MarkPaper> queryWrapper = new QueryWrapper<>();
+        queryWrapper.lambda().eq(MarkPaper::getExamId, examId)
+                .eq(MarkPaper::getCourseId, courseId);
+        return this.list(queryWrapper);
+    }
 }

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

@@ -8,6 +8,8 @@ import javax.annotation.Resource;
 import javax.servlet.http.HttpServletResponse;
 
 import com.qmth.teachcloud.common.bean.result.MarkQuestionResult;
+import com.qmth.teachcloud.mark.bean.cardJson.DescriptionCourse;
+import com.qmth.teachcloud.mark.bean.vo.parseCard.Struct;
 import com.qmth.teachcloud.mark.service.*;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.collections4.MapUtils;