فهرست منبع

微信小程序作答按课程设置

deason 2 سال پیش
والد
کامیت
4cc87ace3f
12فایلهای تغییر یافته به همراه518 افزوده شده و 87 حذف شده
  1. 26 0
      examcloud-core-examwork-api-provider/src/main/java/cn/com/qmth/examcloud/core/examwork/api/controller/DevOpsController.java
  2. 40 52
      examcloud-core-examwork-api-provider/src/main/java/cn/com/qmth/examcloud/core/examwork/api/controller/ExamController.java
  3. 112 0
      examcloud-core-examwork-api-provider/src/main/java/cn/com/qmth/examcloud/core/examwork/api/controller/ExamCourseController.java
  4. 4 7
      examcloud-core-examwork-api-provider/src/main/java/cn/com/qmth/examcloud/core/examwork/api/provider/ExamCloudServiceProvider.java
  5. 0 4
      examcloud-core-examwork-api-provider/src/main/java/cn/com/qmth/examcloud/core/examwork/api/provider/ExamStudentCloudServiceProvider.java
  6. 30 22
      examcloud-core-examwork-dao/src/main/java/cn/com/qmth/examcloud/core/examwork/dao/ExamCourseRelationRepo.java
  7. 19 0
      examcloud-core-examwork-service/src/main/java/cn/com/qmth/examcloud/core/examwork/service/ExamCourseService.java
  8. 82 0
      examcloud-core-examwork-service/src/main/java/cn/com/qmth/examcloud/core/examwork/service/bean/ExamCourseRelationInfo.java
  9. 75 0
      examcloud-core-examwork-service/src/main/java/cn/com/qmth/examcloud/core/examwork/service/bean/ExamCourseRelationQuery.java
  10. 128 0
      examcloud-core-examwork-service/src/main/java/cn/com/qmth/examcloud/core/examwork/service/impl/ExamCourseServiceImpl.java
  11. 2 2
      examcloud-core-examwork-service/src/main/java/cn/com/qmth/examcloud/core/examwork/service/impl/ExamStudentServiceImpl.java
  12. BIN
      examcloud-core-examwork-starter/src/main/resources/templates/weixinAnswerEnabledTemplate.xlsx

+ 26 - 0
examcloud-core-examwork-api-provider/src/main/java/cn/com/qmth/examcloud/core/examwork/api/controller/DevOpsController.java

@@ -0,0 +1,26 @@
+package cn.com.qmth.examcloud.core.examwork.api.controller;
+
+import cn.com.qmth.examcloud.web.support.Naked;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@Api(tags = "运维接口")
+@RestController
+@RequestMapping("${$rmp.ctr.examwork}")
+public class DevOpsController {
+
+    private static final Logger log = LoggerFactory.getLogger(DevOpsController.class);
+
+    @Naked
+    @ApiOperation(value = "运维监控检测接口")
+    @GetMapping("/devops")
+    public Long devops() {
+        return System.currentTimeMillis();
+    }
+
+}

+ 40 - 52
examcloud-core-examwork-api-provider/src/main/java/cn/com/qmth/examcloud/core/examwork/api/controller/ExamController.java

@@ -179,24 +179,23 @@ public class ExamController extends ControllerSupport {
     @ApiOperation(value = "查询考试的课程集合")
     @GetMapping("queryExamCourseList")
     public List<ExamCourseRelationEntity> getExamCourseList(
-            @RequestParam(required = true) Long examId, @RequestParam(required = false) String name,
+            @RequestParam(required = true) Long examId,
+            @RequestParam(required = false) String name,
             @RequestParam(required = false) String level,
             @RequestParam(required = false) Boolean enable) {
 
         ExamEntity one = GlobalHelper.getEntity(examRepo, examId, ExamEntity.class);
         if (null == one) {
-            throw new StatusException("001250", "examId is wrong");
+            throw new StatusException("001250", "考试不存在(" + examId + ")!");
         }
         validateRootOrgIsolation(one.getRootOrgId());
 
         Specification<ExamCourseRelationEntity> specification = (root, query, cb) -> {
             List<Predicate> predicates = new ArrayList<>();
-
             predicates.add(cb.equal(root.get("examId"), examId));
 
             Predicate pr1 = cb.like(root.get("courseName"), toSqlSearchPattern(name));
             Predicate pr2 = cb.like(root.get("courseCode"), toSqlSearchPattern(name));
-
             predicates.add(cb.or(pr1, pr2));
 
             if (StringUtils.isNotBlank(level)) {
@@ -212,19 +211,8 @@ public class ExamController extends ControllerSupport {
 
         PageRequest pageRequest = PageRequest.of(0, 50, Sort.by(Direction.DESC, "updateTime"));
 
-        Page<ExamCourseRelationEntity> page = examCourseRelationRepo.findAll(specification,
-                pageRequest);
-
-        Iterator<ExamCourseRelationEntity> iterator = page.iterator();
-        List<ExamCourseRelationEntity> list = Lists.newArrayList();
-
-        while (iterator.hasNext()) {
-            ExamCourseRelationEntity next = iterator.next();
-            list.add(next);
-        }
-
-        return list;
-
+        Page<ExamCourseRelationEntity> page = examCourseRelationRepo.findAll(specification, pageRequest);
+        return page.getContent();
     }
 
     /**
@@ -248,7 +236,6 @@ public class ExamController extends ControllerSupport {
                                           @RequestParam(required = false) Boolean enable,
                                           @RequestParam(required = false) String propertyKeys) {
         User accessUser = getAccessUser();
-
         PageRequest pageable = PageRequest.of(curPage, pageSize, Sort.by(Direction.DESC, "updateTime", "id"));
 
         UserDataRule userDataRule = super.getUserDataRule(DataRuleType.EXAM);
@@ -279,14 +266,20 @@ public class ExamController extends ControllerSupport {
 
         Page<ExamEntity> page = examRepo.findAll(specification, pageable);
 
-        Iterator<ExamEntity> iterator = page.iterator();
-        List<ExamDomain> list = Lists.newArrayList();
-
+        // 补充查询考试的属性值
         List<String> propertyKeyList = null;
         if (StringUtils.isNotBlank(propertyKeys)) {
             propertyKeyList = RegExpUtil.findAll(propertyKeys, "\\w+");
         }
+        if (propertyKeyList == null) {
+            propertyKeyList = new ArrayList<>();
+        }
+        propertyKeyList.add(ExamProperties.IP_LIMIT.name());
+        propertyKeyList.add(ExamProperties.WEIXIN_ANSWER_ENABLED.name());
 
+
+        Iterator<ExamEntity> iterator = page.iterator();
+        List<ExamDomain> list = Lists.newArrayList();
         while (iterator.hasNext()) {
             ExamEntity next = iterator.next();
             ExamDomain bean = new ExamDomain();
@@ -310,21 +303,15 @@ public class ExamController extends ControllerSupport {
             bean.setSpecialSettingsEnabled(next.getSpecialSettingsEnabled());
             bean.setSpecialSettingsType(next.getSpecialSettingsType());
 
-            if (CollectionUtils.isNotEmpty(propertyKeyList)) {
-                Map<String, String> properties = getProperties(bean.getId(), propertyKeyList);
-                bean.setProperties(properties);
-            }
-
-            DynamicEnumManager manager = ExamProperty.getDynamicEnumManager();
-            DynamicEnum ipLimit = manager.getByName(ExamProperties.IP_LIMIT.name());
+            Map<String, String> properties = this.getProperties(bean.getId(), propertyKeyList);
+            bean.setProperties(properties);
 
-            ExamPropertyEntity propertyEntity = examPropertyRepo.findByExamIdAndKeyId(next.getId(), ipLimit.getId());
-            boolean ipLimited = null != propertyEntity && StringUtils.isNotBlank(propertyEntity.getValue()) && Boolean.parseBoolean(propertyEntity.getValue());
-            bean.setIpLimitSettingsEnabled(ipLimited);
+            // String weixinAnswerEnabled = properties.get(ExamProperties.WEIXIN_ANSWER_ENABLED.name());
+            String ipLimitValue = properties.get(ExamProperties.IP_LIMIT.name());
+            bean.setIpLimitSettingsEnabled(StringUtil.isTrue(ipLimitValue));
         }
 
-        PageInfo<ExamDomain> ret = new PageInfo<>(page, list);
-        return ret;
+        return new PageInfo<>(page, list);
     }
 
     /**
@@ -449,9 +436,16 @@ public class ExamController extends ControllerSupport {
      */
     private Map<String, String> getProperties(Long examId, List<String> propertyKeys) {
         Map<String, String> map = Maps.newHashMap();
-        DynamicEnumManager manager = ExamProperty.getDynamicEnumManager();
+        if (CollectionUtils.isEmpty(propertyKeys)) {
+            return map;
+        }
 
+        DynamicEnumManager manager = ExamProperty.getDynamicEnumManager();
         for (String key : propertyKeys) {
+            if (map.containsKey(key)) {
+                continue;
+            }
+
             DynamicEnum de = manager.getByName(key);
             ExamPropertyEntity one = examPropertyRepo.findByExamIdAndKeyId(examId, de.getId());
             if (null != one) {
@@ -1487,36 +1481,30 @@ public class ExamController extends ControllerSupport {
         return map;
     }
 
-    @ApiOperation(value = "是否可以微信作答", notes = "")
+    @ApiOperation(value = "是否开放微信小程序作答", notes = "")
     @GetMapping("weixinAnswerEnabled/{examId}")
-    public Boolean weixinAnswerEnabled(@PathVariable Long examId) {
-
+    public Boolean weixinAnswerEnabled(@PathVariable Long examId, @RequestParam(required = false) String courseCode) {
         ExamSettingsCacheBean examSettings = CacheHelper.getExamSettings(examId);
 
-        OrgPropertyCacheBean orgConf = CacheHelper.getOrgProperty(examSettings.getRootOrgId(),
-                "WEIXIN_ANSWER_ENABLED");
-        ExamPropertyCacheBean examConf = CacheHelper.getExamProperty(examId,
-                "WEIXIN_ANSWER_ENABLED");
+        OrgPropertyCacheBean orgConf = CacheHelper.getOrgProperty(examSettings.getRootOrgId(), "WEIXIN_ANSWER_ENABLED");
+        ExamPropertyCacheBean examConf = CacheHelper.getExamProperty(examId, "WEIXIN_ANSWER_ENABLED");
 
-        String orgValue = orgConf.getValue();
-        String examValue = examConf.getValue();
-
-        if (!orgConf.getHasValue()) {
-            return false;
-        }
-        if (StringUtils.isBlank(orgValue)) {
+        if (!StringUtil.isTrue(orgConf.getValue())) {
             return false;
         }
 
-        if (StringUtils.isBlank(examValue)) {
+        if (!StringUtil.isTrue(examConf.getValue())) {
             return false;
         }
 
-        if (StringUtil.isTrue(orgValue.toString()) && StringUtil.isTrue(examValue)) {
-            return true;
+        if (StringUtils.isNotBlank(courseCode)) {
+            ExamCourseRelationEntity entity = examCourseRelationRepo.findByExamIdAndCourseCode(examId, courseCode);
+            if (entity != null) {
+                return entity.getWeixinAnswerEnabled();
+            }
         }
 
-        return false;
+        return true;
     }
 
     @ApiOperation(value = "是否支持人脸识别", notes = "")

+ 112 - 0
examcloud-core-examwork-api-provider/src/main/java/cn/com/qmth/examcloud/core/examwork/api/controller/ExamCourseController.java

@@ -0,0 +1,112 @@
+package cn.com.qmth.examcloud.core.examwork.api.controller;
+
+import cn.com.qmth.examcloud.commons.exception.StatusException;
+import cn.com.qmth.examcloud.commons.helpers.poi.ExcelReader;
+import cn.com.qmth.examcloud.commons.helpers.poi.ExcelWriter;
+import cn.com.qmth.examcloud.commons.util.PathUtil;
+import cn.com.qmth.examcloud.core.examwork.service.ExamCourseService;
+import cn.com.qmth.examcloud.core.examwork.service.bean.ExamCourseRelationInfo;
+import cn.com.qmth.examcloud.core.examwork.service.bean.ExamCourseRelationQuery;
+import cn.com.qmth.examcloud.web.config.SystemProperties;
+import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import cn.com.qmth.examcloud.web.support.Naked;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+@RestController
+@Api(tags = "考试课程相关接口")
+@RequestMapping("${$rmp.ctr.examwork}/exam/course")
+public class ExamCourseController extends ControllerSupport {
+
+    @Autowired
+    private ExamCourseService examCourseService;
+
+    @Autowired
+    private SystemProperties systemConfig;
+
+    @PostMapping("/list")
+    @ApiOperation(value = "查询考试相关课程列表(分页)")
+    public Page<ExamCourseRelationInfo> list(@RequestBody ExamCourseRelationQuery req) {
+        return examCourseService.getExamCourseRelationListByPage(req);
+    }
+
+    @PostMapping("/weixinAnswerEnabled")
+    @ApiOperation(value = "(批量)启用或禁用微信小程序作答")
+    public void weixinAnswerEnabled(@RequestParam Long examId, @RequestParam Long[] courseIds, @RequestParam Boolean enabled) {
+        examCourseService.batchUpdateWeixinAnswerEnabled(examId, courseIds, enabled);
+    }
+
+    @ApiOperation(value = "导入-课程的微信小程序作答设置")
+    @PostMapping("/import/weixinAnswerEnabledSetting")
+    public void importSetting(@RequestParam Long examId, @RequestPart(value = "file", required = false) MultipartFile file) {
+        if (file == null) {
+            throw new StatusException("文件不能为空!");
+        }
+
+        List<String[]> lines;
+        try {
+            lines = ExcelReader.readSheetBySax(file.getInputStream(), 1, 3);
+        } catch (Exception e) {
+            throw new StatusException("Excel解析失败!");
+        }
+
+        if (CollectionUtils.isEmpty(lines)) {
+            throw new StatusException("Excel无内容!");
+        }
+
+        for (int n = 1; n < lines.size(); n++) {
+            // 默认跳过第一行
+            String[] values = lines.get(n);
+            String courseCode = values[0];
+            boolean enabled = "是".equals(values[2]);
+
+            if (StringUtils.isBlank(courseCode)) {
+                continue;
+            }
+
+            examCourseService.updateWeixinAnswerEnabled(examId, courseCode, enabled);
+        }
+    }
+
+    @Naked
+    @ApiOperation(value = "导出-课程的微信小程序作答设置")
+    @GetMapping("/export/weixinAnswerEnabledSetting")
+    public void exportSetting(@RequestParam Long examId, @RequestParam(required = false) Boolean weixinAnswerEnabled) {
+        List<ExamCourseRelationInfo> list = examCourseService.getExamCourseRelationList(examId, weixinAnswerEnabled);
+
+        List<Object[]> lines = new ArrayList<>();
+        for (ExamCourseRelationInfo info : list) {
+            lines.add(new Object[]{info.getCourseCode(), info.getCourseName(), info.getWeixinAnswerEnabled() ? "是" : "否"});
+        }
+
+        String filePath = systemConfig.getTempDataDir() + File.separator + System.currentTimeMillis() + ".xlsx";
+        File file = new File(filePath);
+
+        ExcelWriter.write(new String[]{"课程代码", "课程名称", "是否启用微信小程序作答"},
+                new Class[]{String.class, String.class, String.class},
+                lines, new File(filePath));
+
+        exportFile("result.xlsx", file);
+        FileUtils.deleteQuietly(file);
+    }
+
+    @Naked
+    @ApiOperation(value = "下载-课程的微信小程序作答设置模板")
+    @GetMapping("/download/weixinAnswerEnabledTemplate")
+    public void downloadTemplate() {
+        String resourcePath = PathUtil.getResoucePath("templates/weixinAnswerEnabledTemplate.xlsx");
+        exportFile("课程的微信小程序作答设置模板.xlsx", new File(resourcePath));
+    }
+
+}

+ 4 - 7
examcloud-core-examwork-api-provider/src/main/java/cn/com/qmth/examcloud/core/examwork/api/provider/ExamCloudServiceProvider.java

@@ -364,8 +364,8 @@ public class ExamCloudServiceProvider extends ControllerSupport implements ExamC
             predicates.add(cb.equal(root.get("rootOrgId"), rootOrgId));
 
             predicates.add(cb.greaterThanOrEqualTo(root.get("id"), start));
-            if (req.getUd()!=null&&req.getUd().assertNeedQueryRefIds()) {
-            	predicates.add(root.get("id").in(req.getUd().getRefIds()));
+            if (req.getUd() != null && req.getUd().assertNeedQueryRefIds()) {
+                predicates.add(root.get("id").in(req.getUd().getRefIds()));
             }
             if (null != enable) {
                 predicates.add(cb.equal(root.get("enable"), enable));
@@ -424,9 +424,6 @@ public class ExamCloudServiceProvider extends ControllerSupport implements ExamC
         Long examId = req.getExamId();
 
         final long start = null == req.getStart() ? 1 : req.getStart();
-
-        Pageable pageable = PageRequest.of(0, 100, Sort.Direction.ASC, "courseId");
-
         Specification<ExamCourseRelationEntity> specification = (root, query, cb) -> {
             List<Predicate> predicates = new ArrayList<>();
             predicates.add(cb.equal(root.get("examId"), examId));
@@ -440,8 +437,8 @@ public class ExamCloudServiceProvider extends ControllerSupport implements ExamC
             return cb.and(predicates.toArray(new Predicate[predicates.size()]));
         };
 
-        Page<ExamCourseRelationEntity> page = examCourseRelationRepo.findAll(specification,
-                pageable);
+        Pageable pageable = PageRequest.of(0, 100, Sort.Direction.ASC, "courseId");
+        Page<ExamCourseRelationEntity> page = examCourseRelationRepo.findAll(specification, pageable);
 
         Iterator<ExamCourseRelationEntity> iterator = page.iterator();
 

+ 0 - 4
examcloud-core-examwork-api-provider/src/main/java/cn/com/qmth/examcloud/core/examwork/api/provider/ExamStudentCloudServiceProvider.java

@@ -14,7 +14,6 @@ import cn.com.qmth.examcloud.core.basic.api.request.GetStudentReq;
 import cn.com.qmth.examcloud.core.basic.api.response.GetCourseResp;
 import cn.com.qmth.examcloud.core.basic.api.response.GetOrgResp;
 import cn.com.qmth.examcloud.core.basic.api.response.GetStudentResp;
-import cn.com.qmth.examcloud.core.examwork.dao.ExamCourseRelationRepo;
 import cn.com.qmth.examcloud.core.examwork.dao.ExamPaperTypeRelationRepo;
 import cn.com.qmth.examcloud.core.examwork.dao.ExamRepo;
 import cn.com.qmth.examcloud.core.examwork.dao.ExamStudentRepo;
@@ -92,9 +91,6 @@ public class ExamStudentCloudServiceProvider extends ControllerSupport
     @Autowired
     CourseCloudService courseCloudService;
 
-    @Autowired
-    ExamCourseRelationRepo examCourseRelationRepo;
-
     @Autowired
     ExamPaperTypeRelationRepo examPaperTypeRelationRepo;
 

+ 30 - 22
examcloud-core-examwork-dao/src/main/java/cn/com/qmth/examcloud/core/examwork/dao/ExamCourseRelationRepo.java

@@ -1,33 +1,41 @@
 package cn.com.qmth.examcloud.core.examwork.dao;
 
+import cn.com.qmth.examcloud.core.examwork.dao.entity.ExamCourseRelationEntity;
+import cn.com.qmth.examcloud.core.examwork.dao.entity.ExamCourseRelationPK;
 import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
 import org.springframework.data.jpa.repository.Modifying;
 import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
 import org.springframework.data.repository.query.QueryByExampleExecutor;
+import org.springframework.transaction.annotation.Transactional;
 
-import cn.com.qmth.examcloud.core.examwork.dao.entity.ExamCourseRelationEntity;
-import cn.com.qmth.examcloud.core.examwork.dao.entity.ExamCourseRelationPK;
+import java.util.Date;
+
+public interface ExamCourseRelationRepo extends JpaRepository<ExamCourseRelationEntity, ExamCourseRelationPK>,
+        QueryByExampleExecutor<ExamCourseRelationEntity>, JpaSpecificationExecutor<ExamCourseRelationEntity> {
+
+    void deleteByExamId(Long examId);
+
+    void deleteByExamIdAndCourseId(Long examId, Long courseId);
+
+    ExamCourseRelationEntity findByExamIdAndCourseCode(Long examId, String courseCode);
+
+    @Transactional
+    @Modifying
+    @Query("update ExamCourseRelationEntity s set s.courseName = ?1, s.courseLevel  = ?2,s.courseEnable=?3 where s.courseId=?4")
+    void updateCourse(String courseName, String courseLevel, Boolean courseEnable, Long courseId);
+
+    @Transactional
+    @Modifying
+    @Query("update ExamCourseRelationEntity set weixinAnswerEnabled=:enabled, updateTime=:updateTime where examId=:examId and courseId in (:courseIds)")
+    int batchUpdateWeixinAnswerEnabled(@Param("examId") Long examId, @Param("courseIds") Long[] courseIds,
+                                       @Param("enabled") Boolean enabled, @Param("updateTime") Date updateTime);
 
-/**
- * 类注释
- *
- * @author WANGWEI
- * @date 2018年9月20日
- * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
- */
-public interface ExamCourseRelationRepo
-		extends
-			JpaRepository<ExamCourseRelationEntity, ExamCourseRelationPK>,
-			QueryByExampleExecutor<ExamCourseRelationEntity>,
-			JpaSpecificationExecutor<ExamCourseRelationEntity> {
-
-	void deleteByExamId(Long examId);
-
-	void deleteByExamIdAndCourseId(Long examId, Long courseId);
-
-	@Modifying
-	@Query("update ExamCourseRelationEntity s set s.courseName = ?1, s.courseLevel  = ?2,s.courseEnable=?3 where s.courseId=?4")
-	void updateCourse(String courseName, String courseLevel, Boolean courseEnable, Long courseId);
+    @Transactional
+    @Modifying
+    @Query("update ExamCourseRelationEntity set weixinAnswerEnabled=:enabled, updateTime=:updateTime where examId=:examId and courseCode =:courseCode")
+    int updateWeixinAnswerEnabled(@Param("examId") Long examId, @Param("courseCode") String courseCode,
+                                  @Param("enabled") Boolean enabled, @Param("updateTime") Date updateTime);
 
 }

+ 19 - 0
examcloud-core-examwork-service/src/main/java/cn/com/qmth/examcloud/core/examwork/service/ExamCourseService.java

@@ -0,0 +1,19 @@
+package cn.com.qmth.examcloud.core.examwork.service;
+
+import cn.com.qmth.examcloud.core.examwork.service.bean.ExamCourseRelationInfo;
+import cn.com.qmth.examcloud.core.examwork.service.bean.ExamCourseRelationQuery;
+import org.springframework.data.domain.Page;
+
+import java.util.List;
+
+public interface ExamCourseService {
+
+    Page<ExamCourseRelationInfo> getExamCourseRelationListByPage(ExamCourseRelationQuery req);
+
+    List<ExamCourseRelationInfo> getExamCourseRelationList(Long examId, Boolean weixinAnswerEnabled);
+
+    void batchUpdateWeixinAnswerEnabled(Long examId, Long[] courseIds, boolean enabled);
+
+    void updateWeixinAnswerEnabled(Long examId, String courseCode, boolean enabled);
+
+}

+ 82 - 0
examcloud-core-examwork-service/src/main/java/cn/com/qmth/examcloud/core/examwork/service/bean/ExamCourseRelationInfo.java

@@ -0,0 +1,82 @@
+package cn.com.qmth.examcloud.core.examwork.service.bean;
+
+import cn.com.qmth.examcloud.api.commons.exchange.JsonSerializable;
+
+public class ExamCourseRelationInfo implements JsonSerializable {
+
+    private static final long serialVersionUID = 4009839764353162256L;
+
+    private Long examId;
+
+    private Long courseId;
+
+    private String courseCode;
+
+    private String courseName;
+
+    private String courseLevel;
+
+    private Boolean courseEnable;
+
+    /**
+     * 是否开放微信小程序作答
+     */
+    private Boolean weixinAnswerEnabled;
+
+    public Long getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Long examId) {
+        this.examId = examId;
+    }
+
+    public Long getCourseId() {
+        return courseId;
+    }
+
+    public void setCourseId(Long courseId) {
+        this.courseId = courseId;
+    }
+
+    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;
+    }
+
+    public String getCourseLevel() {
+        return courseLevel;
+    }
+
+    public void setCourseLevel(String courseLevel) {
+        this.courseLevel = courseLevel;
+    }
+
+    public Boolean getCourseEnable() {
+        return courseEnable;
+    }
+
+    public void setCourseEnable(Boolean courseEnable) {
+        this.courseEnable = courseEnable;
+    }
+
+    public Boolean getWeixinAnswerEnabled() {
+        return weixinAnswerEnabled;
+    }
+
+    public void setWeixinAnswerEnabled(Boolean weixinAnswerEnabled) {
+        this.weixinAnswerEnabled = weixinAnswerEnabled;
+    }
+
+}

+ 75 - 0
examcloud-core-examwork-service/src/main/java/cn/com/qmth/examcloud/core/examwork/service/bean/ExamCourseRelationQuery.java

@@ -0,0 +1,75 @@
+package cn.com.qmth.examcloud.core.examwork.service.bean;
+
+import cn.com.qmth.examcloud.api.commons.exchange.JsonSerializable;
+import io.swagger.annotations.ApiModelProperty;
+
+public class ExamCourseRelationQuery implements JsonSerializable {
+
+    private static final long serialVersionUID = 4009839764353162256L;
+
+    @ApiModelProperty("当前页数")
+    private Integer pageNo;
+
+    @ApiModelProperty("每页条数")
+    private Integer pageSize;
+
+    private Long examId;
+
+    private String courseCode;
+
+    private String courseName;
+
+    /**
+     * 是否开放微信小程序作答
+     */
+    private Boolean weixinAnswerEnabled;
+
+    public Integer getPageNo() {
+        return pageNo;
+    }
+
+    public void setPageNo(Integer pageNo) {
+        this.pageNo = pageNo;
+    }
+
+    public Integer getPageSize() {
+        return pageSize;
+    }
+
+    public void setPageSize(Integer pageSize) {
+        this.pageSize = pageSize;
+    }
+
+    public Long getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Long examId) {
+        this.examId = examId;
+    }
+
+    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;
+    }
+
+    public Boolean getWeixinAnswerEnabled() {
+        return weixinAnswerEnabled;
+    }
+
+    public void setWeixinAnswerEnabled(Boolean weixinAnswerEnabled) {
+        this.weixinAnswerEnabled = weixinAnswerEnabled;
+    }
+
+}

+ 128 - 0
examcloud-core-examwork-service/src/main/java/cn/com/qmth/examcloud/core/examwork/service/impl/ExamCourseServiceImpl.java

@@ -0,0 +1,128 @@
+package cn.com.qmth.examcloud.core.examwork.service.impl;
+
+import cn.com.qmth.examcloud.commons.exception.StatusException;
+import cn.com.qmth.examcloud.commons.util.SqlUtil;
+import cn.com.qmth.examcloud.core.examwork.dao.ExamCourseRelationRepo;
+import cn.com.qmth.examcloud.core.examwork.dao.entity.ExamCourseRelationEntity;
+import cn.com.qmth.examcloud.core.examwork.service.ExamCourseService;
+import cn.com.qmth.examcloud.core.examwork.service.bean.ExamCourseRelationInfo;
+import cn.com.qmth.examcloud.core.examwork.service.bean.ExamCourseRelationQuery;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.*;
+import org.springframework.data.jpa.domain.Specification;
+import org.springframework.stereotype.Service;
+
+import javax.persistence.criteria.Predicate;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Service
+public class ExamCourseServiceImpl implements ExamCourseService {
+
+    private static final Logger log = LoggerFactory.getLogger(ExamCourseServiceImpl.class);
+
+    @Autowired
+    private ExamCourseRelationRepo examCourseRelationRepo;
+
+    @Override
+    public Page<ExamCourseRelationInfo> getExamCourseRelationListByPage(ExamCourseRelationQuery req) {
+        if (req.getPageNo() == null || req.getPageNo() < 1) {
+            req.setPageNo(1);
+        }
+
+        if (req.getPageSize() == null || req.getPageSize() < 1) {
+            req.setPageSize(10);
+        }
+        if (req.getExamId() == null) {
+            throw new StatusException("请先选择考试!");
+        }
+
+        Specification<ExamCourseRelationEntity> spec = (root, query, cb) -> {
+            List<Predicate> predicates = new ArrayList<>();
+            predicates.add(cb.equal(root.get("examId"), req.getExamId()));
+
+            if (StringUtils.isNotBlank(req.getCourseCode())) {
+                predicates.add(cb.like(root.get("courseCode"), SqlUtil.toSqlRightLike(req.getCourseCode())));
+            }
+            if (StringUtils.isNotBlank(req.getCourseName())) {
+                predicates.add(cb.like(root.get("courseName"), SqlUtil.toSqlRightLike(req.getCourseName())));
+            }
+
+            if (req.getWeixinAnswerEnabled() != null) {
+                predicates.add(cb.equal(root.get("weixinAnswerEnabled"), req.getWeixinAnswerEnabled()));
+            }
+
+            return cb.and(predicates.toArray(new Predicate[predicates.size()]));
+        };
+
+        Sort sort = Sort.by(Sort.Order.desc("updateTime"));
+        Pageable pageable = PageRequest.of(req.getPageNo() - 1, req.getPageSize(), sort);
+        Page<ExamCourseRelationEntity> page = examCourseRelationRepo.findAll(spec, pageable);
+
+        if (!page.hasContent()) {
+            return new PageImpl<>(new ArrayList<>(), pageable, 0);
+        }
+
+        List<ExamCourseRelationInfo> list = page.getContent().stream()
+                .map(entity -> toExamCourseRelationInfo(entity))
+                .collect(Collectors.toList());
+
+        return new PageImpl<>(list, pageable, page.getTotalElements());
+    }
+
+    @Override
+    public List<ExamCourseRelationInfo> getExamCourseRelationList(Long examId, Boolean weixinAnswerEnabled) {
+        Specification<ExamCourseRelationEntity> spec = (root, query, cb) -> {
+            List<Predicate> predicates = new ArrayList<>();
+            predicates.add(cb.equal(root.get("examId"), examId));
+
+            if (weixinAnswerEnabled != null) {
+                predicates.add(cb.equal(root.get("weixinAnswerEnabled"), weixinAnswerEnabled));
+            }
+
+            return cb.and(predicates.toArray(new Predicate[predicates.size()]));
+        };
+
+        List<ExamCourseRelationEntity> list = examCourseRelationRepo.findAll(spec);
+        return list.stream().map(entity -> toExamCourseRelationInfo(entity)).collect(Collectors.toList());
+    }
+
+    private ExamCourseRelationInfo toExamCourseRelationInfo(ExamCourseRelationEntity entity) {
+        ExamCourseRelationInfo info = new ExamCourseRelationInfo();
+        info.setExamId(entity.getExamId());
+        info.setCourseId(entity.getCourseId());
+        info.setCourseCode(entity.getCourseCode());
+        info.setCourseName(entity.getCourseName());
+        info.setCourseLevel(entity.getCourseLevel());
+        info.setCourseEnable(entity.getCourseEnable());
+        info.setWeixinAnswerEnabled(entity.getWeixinAnswerEnabled());
+        return info;
+    }
+
+    @Override
+    public void batchUpdateWeixinAnswerEnabled(Long examId, Long[] courseIds, boolean enabled) {
+        if (examId == null || ArrayUtils.isEmpty(courseIds)) {
+            return;
+        }
+
+        int effect = examCourseRelationRepo.batchUpdateWeixinAnswerEnabled(examId, courseIds, enabled, new Date());
+        log.warn("batchUpdateWeixinAnswerEnabled examId={} courseIds={} enabled={} effectCount={}", examId, courseIds, enabled, effect);
+    }
+
+    @Override
+    public void updateWeixinAnswerEnabled(Long examId, String courseCode, boolean enabled) {
+        if (examId == null || StringUtils.isBlank(courseCode)) {
+            return;
+        }
+
+        int effect = examCourseRelationRepo.updateWeixinAnswerEnabled(examId, courseCode, enabled, new Date());
+        log.warn("updateWeixinAnswerEnabled examId={} courseCode={} enabled={} effectCount={}", examId, courseCode, enabled, effect);
+    }
+
+}

+ 2 - 2
examcloud-core-examwork-service/src/main/java/cn/com/qmth/examcloud/core/examwork/service/impl/ExamStudentServiceImpl.java

@@ -117,8 +117,7 @@ public class ExamStudentServiceImpl implements ExamStudentService {
             List<ExamStudentEntity> top2 = examStudentRepo.findTop2ByExamIdAndCourseId(
                     examStudent.getExamId(), examStudent.getCourseId());
             if (1 > top2.size()) {
-                examCourseRelationRepo.deleteByExamIdAndCourseId(examStudent.getExamId(),
-                        examStudent.getCourseId());
+                examCourseRelationRepo.deleteByExamIdAndCourseId(examStudent.getExamId(), examStudent.getCourseId());
             }
 
             top2 = examStudentRepo.findTop2ByExamIdAndCourseIdAndPaperType(examStudent.getExamId(),
@@ -357,6 +356,7 @@ public class ExamStudentServiceImpl implements ExamStudentService {
         relation.setCourseCode(courseBean.getCode());
         relation.setCourseName(saved.getCourseName());
         relation.setCourseEnable(courseBean.getEnable());
+        relation.setWeixinAnswerEnabled(true);
         examCourseRelationRepo.save(relation);
 
         ExamPaperTypeRelationEntity pt = new ExamPaperTypeRelationEntity();

BIN
examcloud-core-examwork-starter/src/main/resources/templates/weixinAnswerEnabledTemplate.xlsx