deason 9 kuukautta sitten
vanhempi
commit
884c5a1ae1

+ 65 - 71
src/main/java/cn/com/qmth/scancentral/controller/admin/CardController.java

@@ -1,12 +1,22 @@
 package cn.com.qmth.scancentral.controller.admin;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.annotation.Resource;
-import javax.servlet.http.HttpServletRequest;
-
+import cn.com.qmth.scancentral.controller.BaseController;
+import cn.com.qmth.scancentral.enums.LockType;
+import cn.com.qmth.scancentral.service.AdapteFileService;
+import cn.com.qmth.scancentral.service.AnswerCardService;
+import cn.com.qmth.scancentral.service.ExamService;
+import cn.com.qmth.scancentral.vo.ResultVo;
+import cn.com.qmth.scancentral.vo.card.CardEdit;
+import cn.com.qmth.scancentral.vo.card.CardInfo;
+import cn.com.qmth.scancentral.vo.card.CardQuery;
+import com.qmth.boot.api.annotation.Aac;
+import com.qmth.boot.api.constant.ApiConstant;
+import com.qmth.boot.core.collection.PageResult;
+import com.qmth.boot.core.concurrent.service.ConcurrentService;
+import com.qmth.boot.core.exception.ParameterException;
+import com.qmth.boot.core.exception.ReentrantException;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -16,25 +26,10 @@ import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 import org.springframework.web.multipart.MultipartFile;
 
-import com.qmth.boot.api.annotation.Aac;
-import com.qmth.boot.api.constant.ApiConstant;
-import com.qmth.boot.api.utils.RequestUtil;
-import com.qmth.boot.core.concurrent.service.ConcurrentService;
-import com.qmth.boot.core.exception.ReentrantException;
-
-import cn.com.qmth.scancentral.controller.BaseController;
-import cn.com.qmth.scancentral.entity.AnswerCardEntity;
-import cn.com.qmth.scancentral.enums.LockType;
-import cn.com.qmth.scancentral.service.AdapteFileService;
-import cn.com.qmth.scancentral.service.AnswerCardService;
-import cn.com.qmth.scancentral.service.ExamService;
-import cn.com.qmth.scancentral.vo.UriVo;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import net.sf.json.JSONObject;
+import javax.annotation.Resource;
 
 @RestController
-@Api(tags = "卡格式接口")
+@Api(tags = "卡格式相关接口")
 @RequestMapping(ApiConstant.DEFAULT_URI_PREFIX + "/admin/card")
 @Aac(strict = false, auth = true)
 public class CardController extends BaseController {
@@ -53,34 +48,19 @@ public class CardController extends BaseController {
     @Autowired
     private ExamService examService;
 
-    @ApiOperation(value = "卡格式详情")
-    @RequestMapping(value = "/info", method = RequestMethod.POST)
-    public Map<String, Object> info(@RequestParam Long examId) {
-        Map<String, Object> status = new HashMap<String, Object>();
-        status.put("synching", concurrentService.isLocked(LockType.CARD_SYNC + "-" + examId));
-        status.put("updateTime", examService.getById(examId).getCardSyncTime());
-        Map<String, Object> result = new HashMap<String, Object>();
-        result.put("status", status);
-        result.put("answer", answerCardService.listByExamId(examId));
-        result.put("package", new ArrayList<>());
-        return result;
+    @ApiOperation(value = "查询卡格式列表(分页)")
+    @RequestMapping(value = "/list", method = RequestMethod.POST)
+    public PageResult<CardInfo> list(CardQuery query) {
+        return answerCardService.pageQuery(query);
     }
 
-    @ApiOperation(value = "创建/修改题卡卡格式")
-    @RequestMapping(value = "/answer/save", method = RequestMethod.POST)
-    public JSONObject answerSave(@RequestParam Long examId, @RequestParam(required = false) Integer number,
-            @RequestParam(required = false) String subjectCode, @RequestParam(required = false) String parameter,
-            @RequestParam(required = false) String remark, @RequestParam Integer paperCount,
-            @RequestParam Boolean singlePage, @RequestParam String md5, @RequestParam(required = false) Integer dpi,
-            @RequestParam MultipartFile file) {
+    @ApiOperation(value = "删除卡格式")
+    @RequestMapping(value = "/delete", method = RequestMethod.POST)
+    public ResultVo answerDelete(@RequestParam Long examId, @RequestParam Integer number) {
         if (concurrentService.getLock(LockType.CARD_SYNC + "-" + examId).tryLock()) {
             try {
-                JSONObject result = new JSONObject();
-                AnswerCardEntity card = answerCardService.save(getAccessUser(), examId, number, subjectCode, parameter,
-                        remark, paperCount, singlePage, md5, dpi, file);
-                result.accumulate("number", card.getNumber());
-                result.accumulate("updateTime", System.currentTimeMillis());
-                return result;
+                answerCardService.delete(getAccessUser(), examId, number);
+                return new ResultVo(System.currentTimeMillis());
             } finally {
                 concurrentService.getLock(LockType.CARD_SYNC + "-" + examId).unlock();
             }
@@ -89,36 +69,50 @@ public class CardController extends BaseController {
         }
     }
 
-    @ApiOperation(value = "删除答题卡卡格式")
-    @RequestMapping(value = "/answer/delete", method = RequestMethod.POST)
-    public JSONObject answerDelete(@RequestParam Long examId, @RequestParam Integer number) {
-        if (concurrentService.getLock(LockType.CARD_SYNC + "-" + examId).tryLock()) {
+    @ApiOperation(value = "导入卡格式")
+    @RequestMapping(value = "/import", method = RequestMethod.POST)
+    public ResultVo cardImport(CardEdit info, @RequestParam MultipartFile file) {
+        if (info.getExamId() == null) {
+            throw new ParameterException("考试ID不能为空");
+        }
+        if (concurrentService.getLock(LockType.CARD_SYNC + "-" + info.getExamId()).tryLock()) {
             try {
-                answerCardService.delete(getAccessUser(), examId, number);
-                JSONObject result = new JSONObject();
-                result.accumulate("number", number);
-                result.accumulate("updateTime", System.currentTimeMillis());
-                return result;
+                answerCardService.saveCard(info, file);
+                return new ResultVo(System.currentTimeMillis());
             } finally {
-                concurrentService.getLock(LockType.CARD_SYNC + "-" + examId).unlock();
+                concurrentService.getLock(LockType.CARD_SYNC + "-" + info.getExamId()).unlock();
             }
         } else {
             throw new ReentrantException("正在同步卡格式,请稍后再试");
         }
     }
 
-    @ApiOperation(value = "答题卡适配卡格式上传")
-    @RequestMapping(value = "/answer/adapte/upload", method = RequestMethod.POST)
-    public UriVo adapteUpload(HttpServletRequest request, @RequestParam Long examId, @RequestParam Integer cardNumber,
-            @RequestParam MultipartFile file, @RequestParam String md5, @RequestParam Integer dpi) {
-        return adapteFileService.save(RequestUtil.getIpAddress(request), getAccessUser().getRole(), examId, cardNumber,
-                md5, dpi, file);
-    }
+    // @ApiOperation(value = "答题卡适配卡格式上传")
+    // @RequestMapping(value = "/answer/adapte/upload", method = RequestMethod.POST)
+    // public UriVo adapteUpload(HttpServletRequest request, @RequestParam Long examId, @RequestParam Integer cardNumber,
+    //                           @RequestParam MultipartFile file, @RequestParam String md5, @RequestParam Integer dpi) {
+    //     return adapteFileService.save(RequestUtil.getIpAddress(request), getAccessUser().getRole(), examId, cardNumber,
+    //             md5, dpi, file);
+    // }
+    //
+    // @ApiOperation(value = "卡格式详情")
+    // @RequestMapping(value = "/info", method = RequestMethod.POST)
+    // public Map<String, Object> info(@RequestParam Long examId) {
+    //     Map<String, Object> status = new HashMap<String, Object>();
+    //     status.put("synching", concurrentService.isLocked(LockType.CARD_SYNC + "-" + examId));
+    //     status.put("updateTime", examService.getById(examId).getCardSyncTime());
+    //     Map<String, Object> result = new HashMap<String, Object>();
+    //     result.put("status", status);
+    //     result.put("answer", answerCardService.listByExamId(examId));
+    //     result.put("package", new ArrayList<>());
+    //     return result;
+    // }
+    //
+    // @ApiOperation(value = "创建/修改签到表卡格式")
+    // @RequestMapping(value = "/package/save", method = RequestMethod.POST)
+    // public JSONObject packageSave() {
+    //     JSONObject result = new JSONObject();
+    //     return result;
+    // }
 
-    @ApiOperation(value = "创建/修改签到表卡格式")
-    @RequestMapping(value = "/package/save", method = RequestMethod.POST)
-    public JSONObject packageSave() {
-        JSONObject result = new JSONObject();
-        return result;
-    }
 }

+ 7 - 0
src/main/java/cn/com/qmth/scancentral/dao/AnswerCardDao.java

@@ -1,8 +1,15 @@
 package cn.com.qmth.scancentral.dao;
 
 import cn.com.qmth.scancentral.entity.AnswerCardEntity;
+import cn.com.qmth.scancentral.vo.card.CardInfo;
+import cn.com.qmth.scancentral.vo.card.CardQuery;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.github.jeffreyning.mybatisplus.base.MppBaseMapper;
+import org.apache.ibatis.annotations.Param;
 
 public interface AnswerCardDao extends MppBaseMapper<AnswerCardEntity> {
 
+    IPage<CardInfo> pageQuery(Page<CardInfo> page, @Param("query") CardQuery query);
+
 }

+ 13 - 7
src/main/java/cn/com/qmth/scancentral/service/AnswerCardService.java

@@ -1,21 +1,27 @@
 package cn.com.qmth.scancentral.service;
 
-import java.util.List;
-
-import org.springframework.web.multipart.MultipartFile;
-
-import com.github.jeffreyning.mybatisplus.service.IMppService;
-
 import cn.com.qmth.scancentral.bean.User;
 import cn.com.qmth.scancentral.entity.AnswerCardEntity;
 import cn.com.qmth.scancentral.vo.AnswerCardVo;
+import cn.com.qmth.scancentral.vo.card.CardEdit;
+import cn.com.qmth.scancentral.vo.card.CardInfo;
+import cn.com.qmth.scancentral.vo.card.CardQuery;
+import com.github.jeffreyning.mybatisplus.service.IMppService;
+import com.qmth.boot.core.collection.PageResult;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.List;
 
 public interface AnswerCardService extends IMppService<AnswerCardEntity> {
 
+    PageResult<CardInfo> pageQuery(CardQuery query);
+
     int getCountByExam(Long examId);
 
+    void saveCard(CardEdit info, MultipartFile file);
+
     AnswerCardEntity save(User user, Long examId, Integer number, String subjectCode, String parameter, String remark,
-            Integer paperCount, Boolean singlePage, String md5, Integer dpi, MultipartFile file);
+                          Integer paperCount, Boolean singlePage, String md5, Integer dpi, MultipartFile file);
 
     void delete(User user, Long examId, Integer number);
 

+ 92 - 1
src/main/java/cn/com/qmth/scancentral/service/impl/AnswerCardServiceImpl.java

@@ -7,12 +7,19 @@ import cn.com.qmth.scancentral.entity.*;
 import cn.com.qmth.scancentral.enums.CardSource;
 import cn.com.qmth.scancentral.enums.ExamMode;
 import cn.com.qmth.scancentral.service.*;
+import cn.com.qmth.scancentral.util.PageUtil;
 import cn.com.qmth.scancentral.vo.AnswerCardVo;
+import cn.com.qmth.scancentral.vo.card.CardEdit;
+import cn.com.qmth.scancentral.vo.card.CardInfo;
+import cn.com.qmth.scancentral.vo.card.CardQuery;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 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.fasterxml.jackson.databind.ObjectMapper;
 import com.github.jeffreyning.mybatisplus.service.MppServiceImpl;
+import com.qmth.boot.core.collection.PageResult;
 import com.qmth.boot.core.exception.ParameterException;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang.StringUtils;
@@ -59,6 +66,12 @@ public class AnswerCardServiceImpl extends MppServiceImpl<AnswerCardDao, AnswerC
     @Autowired
     private AnswerCardSubjectService answerCardSubjectService;
 
+    @Override
+    public PageResult<CardInfo> pageQuery(CardQuery query) {
+        IPage<CardInfo> iPage = baseMapper.pageQuery(new Page<>(query.getPageNumber(), query.getPageSize()), query);
+        return PageUtil.of(iPage);
+    }
+
     @Override
     public int getCountByExam(Long examId) {
         QueryWrapper<AnswerCardEntity> wrapper = new QueryWrapper<>();
@@ -67,10 +80,84 @@ public class AnswerCardServiceImpl extends MppServiceImpl<AnswerCardDao, AnswerC
         return this.count(wrapper);
     }
 
+    @Override
+    public void saveCard(CardEdit info, MultipartFile file) {
+        ExamEntity exam = examService.getById(info.getExamId());
+        if (exam == null) {
+            throw new ParameterException("考试不存在");
+        }
+
+        if (StringUtils.isNotBlank(info.getSubjectCode())) {
+            SubjectEntity sub = subjectService.findByExamIdAndCode(info.getExamId(), info.getSubjectCode());
+            if (sub == null) {
+                throw new ParameterException("未找到科目,请先同步或创建考生获取科目");
+            }
+        }
+
+        CardFile cardFile;
+        byte[] fileData;
+        String sliceConfig;
+        List<String> sliceName = null;
+        try {
+            fileData = file.getBytes();
+
+            // 解析卡格式文件
+            cardFile = this.parseCardFile(fileData);
+
+            // 提取裁切坐标
+            sliceConfig = cardFile.getSliceConfig().toString();
+            if (ExamMode.CET.equals(exam.getMode())) {
+                sliceName = cardFile.getSliceName();
+            }
+        } catch (IOException e) {
+            throw new ParameterException("文件解析失败", e);
+        }
+
+        int number = this.findMaxCardNumberByExamId(info.getExamId()) + 1;
+
+        String filePath;
+        try {
+            filePath = fileService.uploadAnswerCard(file.getInputStream(), info.getMd5(), info.getExamId(), number);
+        } catch (IOException e) {
+            log.warn("卡格式文件上传失败! examId:{} number:{} err:{}", info.getExamId(), number, e.getMessage());
+            throw new ParameterException("文件上传失败", e);
+        }
+
+        if (StringUtils.isNotBlank(info.getSubjectCode())) {
+            AnswerCardSubjectEntity as = new AnswerCardSubjectEntity();
+            as.setExamId(info.getExamId());
+            as.setCardNumber(number);
+            as.setSubjectCode(info.getSubjectCode());
+            answerCardSubjectService.saveOrUpdateByMultiId(as);
+        }
+
+        AnswerCardEntity entity = new AnswerCardEntity();
+        entity.setExamId(info.getExamId());
+        entity.setNumber(number);
+        entity.setSliceConfig(sliceConfig);
+        entity.setSliceName(sliceName);
+        entity.setPath(filePath);
+        entity.setNeedAdapte(false);
+        entity.setSource(CardSource.CLIENT);
+        entity.setPaperCount(cardFile.getPages().size());
+        entity.setSinglePage(cardFile.getPages().size() == 1);
+        entity.setParameter(info.getParameter());
+        entity.setRemark(info.getRemark());
+        entity.setDpi(info.getDpi());
+        entity.setMd5(info.getMd5());
+        this.saveOrUpdateByMultiId(entity);
+
+        // 提取客观题结构
+        paperStructureService.updateByAnswerCard(cardFile, info.getExamId(), number);
+
+        log.info("卡格式保存成功! examId:{} number:{} subjectCode:{} path:{}",
+                info.getExamId(), number, info.getSubjectCode(), filePath);
+    }
+
     @Transactional
     @Override
     public AnswerCardEntity save(User user, Long examId, Integer number, String subjectCode, String parameter,
-            String remark, Integer paperCount, Boolean singlePage, String md5, Integer dpi, MultipartFile file) {
+                                 String remark, Integer paperCount, Boolean singlePage, String md5, Integer dpi, MultipartFile file) {
         ExamEntity exam = examService.getById(examId);
         if (ExamMode.K12.equals(exam.getMode()) && StringUtils.isBlank(subjectCode)) {
             throw new ParameterException("K12模式不允许创建通卡");
@@ -184,6 +271,10 @@ public class AnswerCardServiceImpl extends MppServiceImpl<AnswerCardDao, AnswerC
             throw new ParameterException("卡格式已被使用,无法删除");
         }
         AnswerCardEntity a = this.findByExamAndNumber(examId, number);
+        if (a == null) {
+            throw new ParameterException("卡格式不存在");
+        }
+
         if (CardSource.WEB.equals(a.getSource())) {
             throw new ParameterException("电子卡格式无法删除");
         }

+ 106 - 0
src/main/java/cn/com/qmth/scancentral/vo/card/CardEdit.java

@@ -0,0 +1,106 @@
+package cn.com.qmth.scancentral.vo.card;
+
+import io.swagger.annotations.ApiModelProperty;
+
+public class CardEdit {
+
+    @ApiModelProperty(value = "考试ID", required = true)
+    private Long examId;
+
+    @ApiModelProperty(value = "卡格式编号", hidden = true)
+    private Integer number;
+
+    @ApiModelProperty(value = "科目代码")
+    private String subjectCode;
+
+    @ApiModelProperty(value = "属性-json内容", hidden = true)
+    private String parameter;
+
+    @ApiModelProperty(value = "备注")
+    private String remark;
+
+    @ApiModelProperty(value = "卡格式文件MD5", required = true)
+    private String md5;
+
+    @ApiModelProperty(value = "DPI", hidden = true)
+    private Integer dpi;
+
+    @ApiModelProperty(value = "张数", hidden = true)
+    private Integer paperCount;
+
+    @ApiModelProperty(value = "单页题卡", hidden = true)
+    private Boolean singlePage;
+
+    public Long getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Long examId) {
+        this.examId = examId;
+    }
+
+    public Integer getNumber() {
+        return number;
+    }
+
+    public void setNumber(Integer number) {
+        this.number = number;
+    }
+
+    public String getSubjectCode() {
+        return subjectCode;
+    }
+
+    public void setSubjectCode(String subjectCode) {
+        this.subjectCode = subjectCode;
+    }
+
+    public String getParameter() {
+        return parameter;
+    }
+
+    public void setParameter(String parameter) {
+        this.parameter = parameter;
+    }
+
+    public String getRemark() {
+        return remark;
+    }
+
+    public void setRemark(String remark) {
+        this.remark = remark;
+    }
+
+    public String getMd5() {
+        return md5;
+    }
+
+    public void setMd5(String md5) {
+        this.md5 = md5;
+    }
+
+    public Integer getPaperCount() {
+        return paperCount;
+    }
+
+    public void setPaperCount(Integer paperCount) {
+        this.paperCount = paperCount;
+    }
+
+    public Integer getDpi() {
+        return dpi;
+    }
+
+    public void setDpi(Integer dpi) {
+        this.dpi = dpi;
+    }
+
+    public Boolean getSinglePage() {
+        return singlePage;
+    }
+
+    public void setSinglePage(Boolean singlePage) {
+        this.singlePage = singlePage;
+    }
+
+}

+ 106 - 0
src/main/java/cn/com/qmth/scancentral/vo/card/CardInfo.java

@@ -0,0 +1,106 @@
+package cn.com.qmth.scancentral.vo.card;
+
+import io.swagger.annotations.ApiModelProperty;
+
+public class CardInfo {
+
+    @ApiModelProperty(value = "考试ID")
+    private Long examId;
+
+    @ApiModelProperty(value = "卡格式编号")
+    private Integer number;
+
+    @ApiModelProperty(value = "科目代码")
+    private String subjectCode;
+
+    @ApiModelProperty(value = "科目名称")
+    private String subjectName;
+
+    @ApiModelProperty(value = "属性-json内容")
+    private String parameter;
+
+    @ApiModelProperty(value = "张数")
+    private Integer paperCount;
+
+    @ApiModelProperty(value = "备注")
+    private String remark;
+
+    @ApiModelProperty(value = "更新时间")
+    private Long updateTime;
+
+    @ApiModelProperty(value = "文件地址")
+    private String url;
+
+    public Long getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Long examId) {
+        this.examId = examId;
+    }
+
+    public Integer getNumber() {
+        return number;
+    }
+
+    public void setNumber(Integer number) {
+        this.number = number;
+    }
+
+    public String getSubjectCode() {
+        return subjectCode;
+    }
+
+    public void setSubjectCode(String subjectCode) {
+        this.subjectCode = subjectCode;
+    }
+
+    public String getSubjectName() {
+        return subjectName;
+    }
+
+    public void setSubjectName(String subjectName) {
+        this.subjectName = subjectName;
+    }
+
+    public String getParameter() {
+        return parameter;
+    }
+
+    public void setParameter(String parameter) {
+        this.parameter = parameter;
+    }
+
+    public Integer getPaperCount() {
+        return paperCount;
+    }
+
+    public void setPaperCount(Integer paperCount) {
+        this.paperCount = paperCount;
+    }
+
+    public String getRemark() {
+        return remark;
+    }
+
+    public void setRemark(String remark) {
+        this.remark = remark;
+    }
+
+    public Long getUpdateTime() {
+        return updateTime;
+    }
+
+    public void setUpdateTime(Long updateTime) {
+        this.updateTime = updateTime;
+    }
+
+    public String getUrl() {
+        return url;
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+}

+ 19 - 0
src/main/java/cn/com/qmth/scancentral/vo/card/CardQuery.java

@@ -0,0 +1,19 @@
+package cn.com.qmth.scancentral.vo.card;
+
+import cn.com.qmth.scancentral.util.PagerQuery;
+import io.swagger.annotations.ApiModelProperty;
+
+public class CardQuery extends PagerQuery {
+
+    @ApiModelProperty(value = "考试ID")
+    private Long examId;
+
+    public Long getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Long examId) {
+        this.examId = examId;
+    }
+
+}

+ 24 - 0
src/main/resources/mapper/AnswerCardMapper.xml

@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="cn.com.qmth.scancentral.dao.AnswerCardDao">
+
+    <select id="pageQuery" resultType="cn.com.qmth.scancentral.vo.card.CardInfo">
+        SELECT t.exam_id,
+        t.number,
+        s.subject_code,
+        sb.name as subject_name,
+        t.parameter,
+        t.paper_count,
+        t.remark,
+        t.path as url,
+        t.update_time
+        from sc_answer_card t
+        left join sc_answer_card_subject s on s.exam_id = t.exam_id and s.card_number = t.number
+        left join sc_subject sb on sb.exam_id = s.exam_id and sb.code = s.subject_code
+        where 1=1
+        <if test="query.examId != null">
+            and t.exam_id = #{query.examId}
+        </if>
+    </select>
+
+</mapper>