Browse Source

3.4.3 update

xiaofei 6 tháng trước cách đây
mục cha
commit
4a94232880
38 tập tin đã thay đổi với 984 bổ sung275 xóa
  1. 5 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/mapper/BasicExamMapper.java
  2. 2 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/BasicExamService.java
  3. 3 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/BasicExamStudentService.java
  4. 2 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/BasicMessageService.java
  5. 26 12
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/ActivitiServiceImpl.java
  6. 6 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/BasicExamServiceImpl.java
  7. 183 5
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/BasicExamStudentServiceImpl.java
  8. 50 4
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/BasicMessageServiceImpl.java
  9. 4 31
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/ExamTaskServiceImpl.java
  10. 8 4
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/TFFlowJoinServiceImpl.java
  11. 10 0
      distributed-print-business/src/main/resources/mapper/BasicExamMapper.xml
  12. 39 1
      distributed-print/install/mysql/upgrade/3.4.3.sql
  13. 6 5
      distributed-print/src/main/java/com/qmth/distributed/print/api/SysController.java
  14. 39 7
      distributed-print/src/main/java/com/qmth/distributed/print/api/admin/DataController.java
  15. 8 11
      distributed-print/src/main/java/com/qmth/distributed/print/start/StartRunning.java
  16. 1 1
      distributed-print/src/test/java/com/qmth/distributed/print/ServiceTest.java
  17. 121 0
      teachcloud-common/src/main/java/com/qmth/teachcloud/common/bean/dto/TSyncDataDto.java
  18. 1 0
      teachcloud-common/src/main/java/com/qmth/teachcloud/common/contant/SystemConstant.java
  19. 2 1
      teachcloud-common/src/main/java/com/qmth/teachcloud/common/enums/MessageEnum.java
  20. 2 1
      teachcloud-common/src/main/java/com/qmth/teachcloud/common/service/impl/BasicCourseServiceImpl.java
  21. 4 0
      teachcloud-common/src/main/java/com/qmth/teachcloud/common/service/impl/SysOrgServiceImpl.java
  22. 64 0
      teachcloud-common/src/main/java/com/qmth/teachcloud/common/service/impl/SysUserServiceImpl.java
  23. 47 0
      teachcloud-common/src/main/java/com/qmth/teachcloud/common/util/SmsSendUtil.java
  24. 1 1
      teachcloud-common/src/main/resources/mapper/BasicCourseMapper.xml
  25. 9 1
      teachcloud-data/pom.xml
  26. 107 102
      teachcloud-data/src/main/java/com/qmth/teachcloud/data/DataUtil.java
  27. 15 3
      teachcloud-data/src/main/java/com/qmth/teachcloud/data/entity/TSyncDataLog.java
  28. 25 0
      teachcloud-data/src/main/java/com/qmth/teachcloud/data/enums/DataType.java
  29. 0 1
      teachcloud-data/src/main/java/com/qmth/teachcloud/data/mapper/TSyncDataMapper.java
  30. 1 0
      teachcloud-data/src/main/java/com/qmth/teachcloud/data/service/DataService.java
  31. 1 1
      teachcloud-data/src/main/java/com/qmth/teachcloud/data/service/TSyncDataService.java
  32. 162 65
      teachcloud-data/src/main/java/com/qmth/teachcloud/data/service/impl/DataServiceImpl.java
  33. 1 0
      teachcloud-data/src/main/java/com/qmth/teachcloud/data/service/impl/TSyncDataLogServiceImpl.java
  34. 9 6
      teachcloud-data/src/main/java/com/qmth/teachcloud/data/service/impl/TSyncDataServiceImpl.java
  35. 1 0
      teachcloud-data/src/main/resources/mapper/TSyncDataMapper.xml
  36. 11 1
      teachcloud-task/src/main/java/com/qmth/teachcloud/task/job/DataSyncJob.java
  37. 1 1
      teachcloud-task/src/main/java/com/qmth/teachcloud/task/job/service/JobService.java
  38. 7 10
      teachcloud-task/src/main/java/com/qmth/teachcloud/task/job/service/impl/JobServiceImpl.java

+ 5 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/mapper/BasicExamMapper.java

@@ -4,9 +4,12 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.qmth.teachcloud.common.bean.dto.DataPermissionRule;
+import com.qmth.teachcloud.common.bean.dto.TSyncDataDto;
 import com.qmth.teachcloud.common.entity.BasicExam;
 import org.apache.ibatis.annotations.Param;
 
+import java.util.List;
+
 /**
  * <p>
  * 考试字典表 Mapper 接口
@@ -21,4 +24,6 @@ public interface BasicExamMapper extends BaseMapper<BasicExam> {
      * @return 分页结果
      */
     IPage<BasicExam> findBasicExamPage(@Param("objectPage") Page<Object> objectPage, @Param("schoolId") Long schoolId, @Param("semesterId") Long semesterId, @Param("enable") Boolean enable, @Param("dpr") DataPermissionRule dpr);
+
+    List<TSyncDataDto> listSyncData();
 }

+ 2 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/BasicExamService.java

@@ -2,6 +2,7 @@ package com.qmth.distributed.print.business.service;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.qmth.teachcloud.common.bean.dto.TSyncDataDto;
 import com.qmth.teachcloud.common.entity.BasicExam;
 import com.qmth.teachcloud.common.enums.ExamModelEnum;
 
@@ -54,4 +55,5 @@ public interface BasicExamService extends IService<BasicExam> {
     boolean enable(Long id, Boolean enable);
 
 
+    List<TSyncDataDto> listSyncData();
 }

+ 3 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/BasicExamStudentService.java

@@ -10,6 +10,7 @@ import com.qmth.distributed.print.business.bean.params.BasicExamStudentParam;
 import com.qmth.distributed.print.business.bean.result.BasicExamStudentResult;
 import com.qmth.distributed.print.business.entity.BasicCardRule;
 import com.qmth.distributed.print.business.entity.ExamStudent;
+import com.qmth.teachcloud.common.bean.sync.TSyncDataStudent;
 import com.qmth.teachcloud.common.entity.BasicExam;
 import com.qmth.teachcloud.common.entity.BasicExamStudent;
 import com.qmth.teachcloud.common.entity.SysUser;
@@ -93,4 +94,6 @@ public interface BasicExamStudentService extends IService<BasicExamStudent> {
     void clearPaperNumberAndPaperTypeById(List<Long> ids);
 
     void clearPaperNumberAndPaperTypeByExamIdAndPaperNumber(Long examId, String paperNumber);
+
+    boolean saveBasicExamStudentFormSync(Long schoolId, Long examId, List<TSyncDataStudent> examStudentDataVo);
 }

+ 2 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/BasicMessageService.java

@@ -18,6 +18,8 @@ import java.util.List;
  */
 public interface BasicMessageService extends IService<BasicMessage> {
 
+    void saveMessageSendLog(Long schoolId, Long userId, String userName, String mobileNumber, String variableParams, MessageEnum messageType);
+
     /**
      * 发送给命题老师-命题待办提醒
      *

+ 26 - 12
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/ActivitiServiceImpl.java

@@ -389,7 +389,15 @@ public class ActivitiServiceImpl implements ActivitiService {
      * @param map
      */
     protected void flowApproveStart(Map<String, Object> map) {
-        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
+        Long userId = map.containsKey("userId") ? Long.valueOf(map.get("userId").toString()) : null;
+        Long schoolId = map.containsKey("schoolId") ? Long.valueOf(map.get("schoolId").toString()) : null;
+        Long orgId = map.containsKey("orgId") ? Long.valueOf(map.get("orgId").toString()) : null;
+        if(schoolId == null || userId == null){
+            SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
+            schoolId = sysUser.getSchoolId();
+            userId = sysUser.getId();
+            orgId = sysUser.getOrgId();
+        }
         Optional.ofNullable(map.get(SystemConstant.FLOW_ID)).orElseThrow(() -> ExceptionResultEnum.ERROR.exception("流程id不能为空"));
         String flowId = (String) map.get(SystemConstant.FLOW_ID);
         TFCustomTypeEnum flowType = (TFCustomTypeEnum) map.get(SystemConstant.FLOW_TYPE);
@@ -404,13 +412,13 @@ public class ActivitiServiceImpl implements ActivitiService {
         if (Objects.nonNull(flowJoinTypeEnum) && flowJoinTypeEnum == FlowJoinTypeEnum.RESTART) {//重新提交
             Long oldFlowId = (Long) map.get(SystemConstant.OLD_FLOW_ID);
             tfFlowApprove = tfFlowApproveService.findByFlowId(oldFlowId);
-            tfFlowApprove.insertInfo(sysUser.getId());
-            tfFlowApprove.updateInfo(sysUser.getId());
+            tfFlowApprove.insertInfo(userId);
+            tfFlowApprove.updateInfo(userId);
             tfFlowApprove.setFlowId(SystemConstant.convertIdToLong(flowId));
             tfFlowApprove.setStatus(FlowStatusEnum.REJECT);
             tfFlowApprove.setSetup(FlowApproveSetupEnum.SUBMIT.getSetup());
         } else {
-            tfFlowApprove = new TFFlowApprove(sysUser.getSchoolId(), sysUser.getOrgId(), SystemConstant.convertIdToLong(flowId), sysUser.getId(), flowStatusEnum, sysUser.getId());
+            tfFlowApprove = new TFFlowApprove(schoolId, orgId, SystemConstant.convertIdToLong(flowId), userId, flowStatusEnum, userId);
         }
         tfFlowApproveService.save(tfFlowApprove);
 
@@ -429,7 +437,7 @@ public class ActivitiServiceImpl implements ActivitiService {
 //        tfFlowJoinList.get(0).setObjectTable(flowType.getTable());
 //        tfFlowJoinService.updateById(tfFlowJoinList.get(0));
         Task task = taskService.createTaskQuery().processInstanceId(flowId).singleResult();
-        tfFlowLogService.save(new TFFlowLog(sysUser.getSchoolId(), sysUser.getOrgId(), SystemConstant.convertIdToLong(flowId), objectId, sysUser.getId(), sysUser.getId(), Objects.nonNull(map.get(SystemConstant.APPROVE_REMARK)) ? (String) map.get(SystemConstant.APPROVE_REMARK) : "提交流程", approveId, FlowApproveOperationEnum.SUBMIT, flowType.getTable(), Objects.nonNull(task) ? Long.parseLong(task.getId()) : null));
+        tfFlowLogService.save(new TFFlowLog(schoolId, orgId, SystemConstant.convertIdToLong(flowId), objectId, userId, userId, Objects.nonNull(map.get(SystemConstant.APPROVE_REMARK)) ? (String) map.get(SystemConstant.APPROVE_REMARK) : "提交流程", approveId, FlowApproveOperationEnum.SUBMIT, flowType.getTable(), Objects.nonNull(task) ? Long.parseLong(task.getId()) : null));
     }
 
     /**
@@ -448,7 +456,7 @@ public class ActivitiServiceImpl implements ActivitiService {
         Optional.ofNullable(task).orElseThrow(() -> ExceptionResultEnum.ERROR.exception("流程任务为空或该流程已被他人审核,请刷新再试!"));
         Long flowId = SystemConstant.convertIdToLong(task.getProcessInstanceId());
         List<Task> taskList = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).list();
-        
+
         if (!CollectionUtils.isEmpty(map) && Objects.nonNull(map.get(SystemConstant.APPROVE_OPERATION))) {
             FlowApprovePassEnum approve = (FlowApprovePassEnum) map.get(SystemConstant.APPROVE_OPERATION);
             if (approve == FlowApprovePassEnum.PASS) {
@@ -1605,9 +1613,15 @@ public class ActivitiServiceImpl implements ActivitiService {
     @Override
     @Transactional
     public Map<String, Object> customFlowStart(Map<String, Object> map) {
-        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
+        Long userId = map.containsKey("userId") ? Long.valueOf(map.get("userId").toString()) : null;
+        Long schoolId = map.containsKey("schoolId") ? Long.valueOf(map.get("schoolId").toString()) : null;
+        if(schoolId == null || userId == null){
+            SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
+            schoolId = sysUser.getSchoolId();
+            userId = sysUser.getId();
+        }
         Long approveId = (Long) map.get(SystemConstant.APPROVE_ID);
-        TFCustomFlow tfCustomFlow = tfCustomFlowService.findMaxVersion(sysUser.getSchoolId(), null, TFCustomTypeEnum.ELECTRON_FLOW);
+        TFCustomFlow tfCustomFlow = tfCustomFlowService.findMaxVersion(schoolId, null, TFCustomTypeEnum.ELECTRON_FLOW);
         Optional.ofNullable(tfCustomFlow).orElseThrow(() -> ExceptionResultEnum.ERROR.exception("未找到自定义流程数据"));
 
         TFCustomFlowEntity tfCustomFlowEntity = null;
@@ -1616,11 +1630,11 @@ public class ActivitiServiceImpl implements ActivitiService {
         if (Objects.nonNull(flowJoinTypeEnum) && flowJoinTypeEnum == FlowJoinTypeEnum.RESTART) {//重新提交
             Long oldFlowId = (Long) map.get(SystemConstant.OLD_FLOW_ID);
             tfCustomFlowEntity = tfCustomFlowEntityService.findByFlowId(oldFlowId);
-            tfCustomFlowEntity.insertInfo(sysUser.getId());
-            tfCustomFlowEntity.updateInfo(sysUser.getId());
+            tfCustomFlowEntity.insertInfo(userId);
+            tfCustomFlowEntity.updateInfo(userId);
             flowProcessVarMap = this.getFlowProcessVarMap(tfCustomFlowEntity);
         } else {//否则新增
-            tfCustomFlowEntity = new TFCustomFlowEntity(tfCustomFlow.getId(), sysUser.getId());
+            tfCustomFlowEntity = new TFCustomFlowEntity(tfCustomFlow.getId(), userId);
             flowProcessVarMap = this.getFlowProcessVarMap(tfCustomFlow);
         }
         Map<String, CustomFlowVarDto> agginessMap = (Map<String, CustomFlowVarDto>) flowProcessVarMap.get(SystemConstant.AGGINESS_MAP);
@@ -1646,7 +1660,7 @@ public class ActivitiServiceImpl implements ActivitiService {
         map.remove(SystemConstant.FLOW_SUBMIT);
         map.computeIfAbsent(SystemConstant.ACT_FLOW_ID, v -> tfCustomFlow.getActFlowId());
         tfCustomFlowEntity.setFlowProcessVar(JacksonUtil.parseJson(map));
-        tfCustomFlow.setUpdateId(sysUser.getId());
+        tfCustomFlow.setUpdateId(userId);
         tfCustomFlowEntityService.save(tfCustomFlowEntity);
         tfCustomFlowService.updateById(tfCustomFlow);
         return map;

+ 6 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/BasicExamServiceImpl.java

@@ -12,6 +12,7 @@ import com.qmth.distributed.print.business.mapper.BasicExamMapper;
 import com.qmth.distributed.print.business.service.*;
 import com.qmth.distributed.print.business.util.CodeUtils;
 import com.qmth.teachcloud.common.bean.dto.DataPermissionRule;
+import com.qmth.teachcloud.common.bean.dto.TSyncDataDto;
 import com.qmth.teachcloud.common.contant.SystemConstant;
 import com.qmth.teachcloud.common.entity.BasicExam;
 import com.qmth.teachcloud.common.entity.BasicExamStudent;
@@ -156,4 +157,9 @@ public class BasicExamServiceImpl extends ServiceImpl<BasicExamMapper, BasicExam
         return this.update(updateWrapper);
     }
 
+    @Override
+    public List<TSyncDataDto> listSyncData() {
+        return this.baseMapper.listSyncData();
+    }
+
 }

+ 183 - 5
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/BasicExamStudentServiceImpl.java

@@ -9,11 +9,13 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.qmth.distributed.print.business.bean.dto.DeleteBasicExamStudentStatusDto;
 import com.qmth.distributed.print.business.bean.dto.ExamStudentDto;
+import com.qmth.distributed.print.business.bean.dto.importFile.BasicExamStudentImport;
 import com.qmth.distributed.print.business.bean.params.BasicExamStudentParam;
 import com.qmth.distributed.print.business.bean.query.BasicExamStudentPageQuery;
 import com.qmth.distributed.print.business.bean.query.BasicExamStudentQuery;
 import com.qmth.distributed.print.business.bean.result.BasicExamStudentResult;
 import com.qmth.distributed.print.business.entity.*;
+import com.qmth.teachcloud.common.bean.sync.TSyncDataStudent;
 import com.qmth.teachcloud.common.enums.ExamNumberStyleEnum;
 import com.qmth.distributed.print.business.enums.RequiredFieldsEnum;
 import com.qmth.distributed.print.business.mapper.BasicExamStudentMapper;
@@ -43,6 +45,7 @@ import org.springframework.transaction.annotation.Transactional;
 import javax.annotation.Resource;
 import java.lang.reflect.Field;
 import java.util.*;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 
 /**
@@ -217,7 +220,7 @@ public class BasicExamStudentServiceImpl extends ServiceImpl<BasicExamStudentMap
         String teacherCode = basicExamStudentParam.getTeacherCode();
         String paperType = basicExamStudentParam.getPaperType();
 
-        if(StringUtils.isNotBlank(studentCode) && !studentCode.matches(SystemConstant.REGULAR_EXPRESSION_OF_STUDENT_CODE)){
+        if (StringUtils.isNotBlank(studentCode) && !studentCode.matches(SystemConstant.REGULAR_EXPRESSION_OF_STUDENT_CODE)) {
             throw ExceptionResultEnum.ERROR.exception("学号只能由字母、数字组成");
         }
 
@@ -241,10 +244,10 @@ public class BasicExamStudentServiceImpl extends ServiceImpl<BasicExamStudentMap
                     teacherId = sysUser.getId();
                     // 校验同课程、同教学班下任课老师必须相同
                     List<BasicExamStudent> basicExamStudentList = this.listByExamIdAndCourseIdAndTeachClassName(basicExamStudentParam.getExamId(), basicExamStudentParam.getCourseId(), basicExamStudentParam.getTeachClassName());
-                    if(CollectionUtils.isNotEmpty(basicExamStudentList)){
+                    if (CollectionUtils.isNotEmpty(basicExamStudentList)) {
                         long count = basicExamStudentList.stream().filter(m -> m.getTeacherId() != null && !sysUser.getId().equals(m.getTeacherId())).count();
-                        if(count > 0){
-                            throw ExceptionResultEnum.ERROR.exception("教学班["+basicExamStudentParam.getTeachClassName()+"]存在其它任课老师,教学班的任课老师必须相同");
+                        if (count > 0) {
+                            throw ExceptionResultEnum.ERROR.exception("教学班[" + basicExamStudentParam.getTeachClassName() + "]存在其它任课老师,教学班的任课老师必须相同");
                         }
                     }
                 }
@@ -486,7 +489,7 @@ public class BasicExamStudentServiceImpl extends ServiceImpl<BasicExamStudentMap
         for (Map.Entry<String, List<BasicExamStudent>> entry : stringMap.entrySet()) {
             BasicExamStudent basicExamStudent = entry.getValue().get(0);
             AbInfoVo abInfoVo = markStudentService.findExamTaskPaperTypeOpenStatus(examId, entry.getKey());
-            boolean containPaperType = abInfoVo!= null && (ExamNumberStyleEnum.PRINT.equals(abInfoVo.getExamNumberStyle()) || (ExamNumberStyleEnum.FILL.equals(abInfoVo.getExamNumberStyle()) && !abInfoVo.getOpenAb()));
+            boolean containPaperType = abInfoVo != null && (ExamNumberStyleEnum.PRINT.equals(abInfoVo.getExamNumberStyle()) || (ExamNumberStyleEnum.FILL.equals(abInfoVo.getExamNumberStyle()) && !abInfoVo.getOpenAb()));
             MarkPaper markPaper = markPaperService.getByExamIdAndPaperNumber(examId, entry.getKey());
             if (markPaper == null && ExamModelEnum.MODEL4.equals(basicExam.getExamModel())) {
                 String paperType = SystemConstant.DEFAULT_PAPER_TYPE_A;
@@ -574,4 +577,179 @@ public class BasicExamStudentServiceImpl extends ServiceImpl<BasicExamStudentMap
                 .eq(BasicExamStudent::getPaperNumber, paperNumber);
         this.update(updateWrapper);
     }
+
+    @Override
+    public boolean saveBasicExamStudentFormSync(Long schoolId, Long examId, List<TSyncDataStudent> examStudentDataVoList) {
+        BasicExam basicExam = basicExamService.getById(examId);
+
+        List<BasicExamStudent> basicExamStudentList = this.list(new QueryWrapper<BasicExamStudent>().lambda()
+                .select(BasicExamStudent::getId, BasicExamStudent::getCourseId, BasicExamStudent::getStudentCode, BasicExamStudent::getPaperNumber, BasicExamStudent::getPaperType, BasicExamStudent::getExamStartTime, BasicExamStudent::getExamEndTime)
+                .eq(BasicExamStudent::getSchoolId, schoolId).eq(BasicExamStudent::getExamId, examId));
+        Map<String, BasicExamStudent> courseIdStudentCodeMap = basicExamStudentList.stream().collect(Collectors.toMap(k -> k.getCourseId() + SystemConstant.HYPHEN + k.getStudentCode(), Function.identity(), (v1, v2) -> v1));
+
+        BasicSchool basicSchool = commonCacheService.schoolCache(schoolId);
+        // 学校设置强制校验卷型或者模式4
+        boolean needPaperNumber = (basicSchool.getHasPaperNumber() != null && basicSchool.getHasPaperNumber());
+        // 试卷编号->课程
+        Map<String, Long> paperNumberCourseIdMap = new HashMap<>();
+        // 试卷编号->考试时间
+        Map<String, String> paperNumberExamTimeMap = basicExamStudentList.stream().filter(m -> StringUtils.isNotBlank(m.getPaperNumber())).collect(Collectors.toMap(BasicExamStudent::getPaperNumber, m -> m.getExamStartTime() + "-" + m.getExamEndTime(), (v1, v2) -> v1));
+        Map<String, Long> basicCourseIdMap = new HashMap<>();
+        // 课程id+教学班名称->任课老师Id
+        Map<String, Long> courseTeachClassTeacherMap = new HashMap<>();
+        // 课程学号唯一
+        List<String> courseCodeStudentCodeList = new ArrayList<>();
+
+        List<BasicExamStudent> basicExamStudents = new ArrayList<>();
+
+        for (TSyncDataStudent tSyncDataStudent : examStudentDataVoList) {
+            BasicExamStudent basicExamStudent = new BasicExamStudent();
+            BeanUtils.copyProperties(tSyncDataStudent, basicExamStudent);
+            basicExamStudent.setSchoolId(schoolId);
+            basicExamStudent.setSemesterId(Long.valueOf(basicExam.getSemesterId()));
+            basicExamStudent.setExamId(examId);
+
+            StringJoiner stringJoiner = new StringJoiner(";");
+            // 学号校验
+            if (StringUtils.isNotBlank(basicExamStudent.getStudentCode()) && !basicExamStudent.getStudentCode().matches(SystemConstant.REGULAR_EXPRESSION_OF_STUDENT_CODE)) {
+                stringJoiner.add("学号只能由字母、数字组成");
+            }
+
+            if (ExamModelEnum.MODEL4.equals(basicExam.getExamModel())) {
+                if (basicExamStudent.getPaperType() == null) {
+                    basicExamStudent.setPaperType(SystemConstant.DEFAULT_PAPER_TYPE_A);
+                }
+            }
+            // 任课老师和任课老师工号都有值或都没值
+            if (StringUtils.isNotBlank(tSyncDataStudent.getTeacherCode()) && StringUtils.isBlank(tSyncDataStudent.getTeacherName())) {
+                stringJoiner.add(RequiredFieldsEnum.TEACHER_NAME.getName() + "必填");
+            }
+            if (StringUtils.isNotBlank(tSyncDataStudent.getTeacherName()) && StringUtils.isBlank(tSyncDataStudent.getTeacherCode())) {
+                stringJoiner.add(RequiredFieldsEnum.TEACHER_CODE.getName() + "必填");
+            }
+
+            // 解析考试日期和考试时间
+//            if (StringUtils.isNoneBlank(tSyncDataStudent.getExamDate(), tSyncDataStudent.getExamTime())) {
+//                try {
+//                    Map<String, Object> timeMap = ConvertUtil.analyzeExamTime(basicExamStudentImport.getExamDate(), basicExamStudentImport.getExamTime());
+//                    basicExamStudent.setExamStartTime(Long.valueOf(String.valueOf(timeMap.get("startTime"))));
+//                    basicExamStudent.setExamEndTime(Long.valueOf(String.valueOf(timeMap.get("endTime"))));
+//
+//                    // 反向更新examDate为标准日期格式,
+//                    for (CodeNameEnableDisabledValue codeNameEnableDisabledValue : basicExamStudentImport.getRequiredFieldList()) {
+//                        if (codeNameEnableDisabledValue.getCode().equals(RequiredFieldsEnum.EXAM_DATE.getCode())) {
+//                            codeNameEnableDisabledValue.setValue(String.valueOf(timeMap.get("dateStr")));
+//                        }
+//                    }
+//                } catch (Exception e) {
+//                    stringJoiner.add(e.getMessage());
+//                }
+//            }
+
+            // 校验课程开课学院和课程代码
+            if (StringUtils.isNoneBlank(tSyncDataStudent.getCourseCode(), tSyncDataStudent.getCourseCollegeName())) {
+                String key = tSyncDataStudent.getCourseCode() + SystemConstant.HYPHEN + tSyncDataStudent.getCourseCollegeName();
+                if (!basicCourseIdMap.containsKey(key)) {
+                    List<SysOrg> sysOrgList = sysOrgService.getSecondOrg(schoolId, tSyncDataStudent.getCourseCollegeName());
+                    if (CollectionUtils.isEmpty(sysOrgList)) {
+                        stringJoiner.add("开课学院[" + tSyncDataStudent.getCourseCollegeName() + "]在学院层级不存在");
+                    } else if (sysOrgList.size() == 1) {
+                        SysOrg sysOrg = sysOrgList.get(0);
+                        // 校验课程代码和开课学院
+                        BasicCourse basicCourse = basicCourseService.getByTeachRoomIdAndCode(sysOrg.getId(), tSyncDataStudent.getCourseCode());
+                        if (Objects.isNull(basicCourse)) {
+                            stringJoiner.add("课程代码[" + tSyncDataStudent.getCourseCode() + "]在开课学院[" + tSyncDataStudent.getCourseCollegeName() + "]不存在");
+                        } else {
+                            basicExamStudent.setCourseId(basicCourse.getId());
+                            basicCourseIdMap.put(key, basicCourse.getId());
+                        }
+                    } else {
+                        stringJoiner.add("开课学院[" + tSyncDataStudent.getCourseCollegeName() + "]存在多个相同值");
+                    }
+                } else {
+                    basicExamStudent.setCourseId(basicCourseIdMap.get(key));
+                }
+            }
+
+            // 校验任课老师工号和姓名
+            if (StringUtils.isNoneBlank(tSyncDataStudent.getTeacherCode(), tSyncDataStudent.getTeacherName())) {
+                SysUser sysUser = sysUserService.getByLoginName(schoolId, tSyncDataStudent.getTeacherCode());
+                if (sysUser == null) {
+                    stringJoiner.add("任课老师工号[" + tSyncDataStudent.getTeacherCode() + "]用户不存在");
+                } else {
+                    if (!sysUser.getEnable()) {
+                        stringJoiner.add("任课老师工号[" + tSyncDataStudent.getTeacherCode() + "]用户已禁用");
+                    } else if (!sysUser.getRealName().equals(tSyncDataStudent.getTeacherName())) {
+                        stringJoiner.add("任课老师[" + tSyncDataStudent.getTeacherName() + "]与用户管理中姓名[" + sysUser.getRealName() + "]不一致");
+                    } else {
+                        basicExamStudent.setTeacherId(sysUser.getId());
+                    }
+                }
+
+                // 校验同课程下,同一教学班只能有一个任课老师
+                String courseTeachClassTeacherKey = basicExamStudent.getCourseId() + basicExamStudent.getTeachClassName();
+                if (courseTeachClassTeacherMap.containsKey(courseTeachClassTeacherKey)) {
+                    Long teacherId = courseTeachClassTeacherMap.get(courseTeachClassTeacherKey);
+                    if ((teacherId == null && basicExamStudent.getTeacherId() != null) || (teacherId != null && basicExamStudent.getTeacherId() == null) || (teacherId != null && !teacherId.equals(basicExamStudent.getTeacherId()))) {
+                        stringJoiner.add("同课程同教学班,只允许设置一个任课老师");
+                    }
+                } else {
+                    courseTeachClassTeacherMap.put(courseTeachClassTeacherKey, basicExamStudent.getTeacherId());
+                }
+            }
+
+            if (basicExamStudent.getCourseId() != null) {
+                if (courseIdStudentCodeMap.containsKey(basicExamStudent.getCourseId() + SystemConstant.HYPHEN + basicExamStudent.getStudentCode())) {
+                    BasicExamStudent student = courseIdStudentCodeMap.get(basicExamStudent.getCourseId() + SystemConstant.HYPHEN + basicExamStudent.getStudentCode());
+                    if (StringUtils.isNotBlank(student.getPaperNumber()) && !student.getPaperNumber().equals(basicExamStudent.getPaperNumber())) {
+                        throw ExceptionResultEnum.ERROR.exception("不允许修改试卷编号");
+                    } else {
+                        basicExamStudent.setId(student.getId());
+                        basicExamStudent.setPaperType(student.getPaperType());
+                    }
+                }
+
+                if (StringUtils.isNotBlank(basicExamStudent.getPaperNumber())) {
+                    if (paperNumberCourseIdMap.containsKey(basicExamStudent.getPaperNumber())) {
+                        if (!paperNumberCourseIdMap.get(basicExamStudent.getPaperNumber()).equals(basicExamStudent.getCourseId())) {
+                            stringJoiner.add("试卷编号[" + basicExamStudent.getPaperNumber() + "]不能绑定多个课程");
+                        }
+                    } else {
+                        long count = basicExamStudentList.stream().filter(m -> m.getPaperNumber() != null && m.getPaperNumber().equals(basicExamStudent.getPaperNumber()) && !Objects.equals(m.getCourseId(), basicExamStudent.getCourseId())).count();
+                        if (count > 0) {
+                            stringJoiner.add("试卷编号[" + basicExamStudent.getPaperNumber() + "]已绑定其它课程");
+                        } else {
+                            paperNumberCourseIdMap.put(basicExamStudent.getPaperNumber(), basicExamStudent.getCourseId());
+                        }
+                    }
+
+                    // 同一试卷编号只能对应同一考试时间
+                    if (basicExamStudent.getExamStartTime() != null && basicExamStudent.getExamEndTime() != null) {
+                        String examTimeValue = basicExamStudent.getExamStartTime() + "-" + basicExamStudent.getExamEndTime();
+                        if (paperNumberExamTimeMap.containsKey(basicExamStudent.getPaperNumber())) {
+                            if (!paperNumberExamTimeMap.get(basicExamStudent.getPaperNumber()).equals(examTimeValue)) {
+                                stringJoiner.add("试卷编号[" + basicExamStudent.getPaperNumber() + "]只能有相同考试时间");
+                            }
+                        } else {
+                            paperNumberExamTimeMap.put(basicExamStudent.getPaperNumber(), examTimeValue);
+                        }
+                    }
+                }
+
+                // 校验课程学号唯一
+                String courseCodeStudentCodeKey = basicExamStudent.getCourseId() + tSyncDataStudent.getStudentCode();
+                if (courseCodeStudentCodeList.contains(courseCodeStudentCodeKey)) {
+                    stringJoiner.add(String.format("课程代码[%s],开课学院[%s],学号[%s]存在重复考生", tSyncDataStudent.getCourseCode(), tSyncDataStudent.getCourseCollegeName(), tSyncDataStudent.getStudentCode()));
+                } else {
+                    courseCodeStudentCodeList.add(courseCodeStudentCodeKey);
+                }
+            }
+
+            parserRequiredField(basicExamStudent);
+            basicExamStudents.add(basicExamStudent);
+        }
+
+        this.saveOrUpdateBatch(basicExamStudents, 2000);
+        return true;
+    }
 }

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

@@ -1,7 +1,6 @@
 package com.qmth.distributed.print.business.service.impl;
 
 import com.alibaba.fastjson.JSON;
-import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -12,10 +11,8 @@ import com.qmth.teachcloud.common.bean.result.SmsResponseResult;
 import com.qmth.teachcloud.common.enums.MessageEnum;
 import com.qmth.distributed.print.business.mapper.BasicMessageMapper;
 import com.qmth.distributed.print.business.service.BasicMessageService;
-import com.qmth.distributed.print.business.service.ExamTaskService;
 import com.qmth.teachcloud.common.bean.dto.DataPermissionRule;
 import com.qmth.teachcloud.common.bean.params.ApproveUserResult;
-import com.qmth.teachcloud.common.contant.SpringContextHolder;
 import com.qmth.teachcloud.common.contant.SystemConstant;
 import com.qmth.teachcloud.common.entity.SysConfig;
 import com.qmth.teachcloud.common.entity.SysUser;
@@ -29,7 +26,6 @@ import com.qmth.teachcloud.common.util.ServletUtil;
 import com.qmth.teachcloud.common.util.SmsSendUtil;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.stereotype.Service;
-import org.springframework.util.CollectionUtils;
 
 import javax.annotation.Resource;
 import java.util.*;
@@ -189,6 +185,56 @@ public class BasicMessageServiceImpl extends ServiceImpl<BasicMessageMapper, Bas
         }
     }
 
+    @Override
+    public void saveMessageSendLog(Long schoolId, Long userId, String userName, String mobileNumber, String variableParams, MessageEnum messageType) {
+        BasicMessage basicMessage = new BasicMessage();
+        String templateCode = null;
+        try {
+            // code和content
+            Map<String, String> enumInfo = smsSendUtil.getCodeAndContentByEnum(messageType);
+            if (!enumInfo.containsKey("templateCode")) {
+                throw ExceptionResultEnum.ERROR.exception("未找到短信模板Code");
+            }
+            templateCode = enumInfo.get("templateCode");
+            if (StringUtils.isBlank(templateCode)) {
+                throw ExceptionResultEnum.ERROR.exception("阿里云短信模板Code必填");
+            }
+
+            if (StringUtils.isBlank(mobileNumber)) {
+                throw ExceptionResultEnum.ERROR.exception("用户手机号必填");
+            }
+            if (StringUtils.isBlank(variableParams)) {
+                throw ExceptionResultEnum.ERROR.exception("短信内容参数值必填");
+            }
+
+            // 调用阿里云短信平台发送短信
+            Map<String, Object> templateParam = JSON.parseObject(variableParams, Map.class);
+            SmsResponseResult smsResponseResult = smsSendUtil.sendSms(schoolId, mobileNumber, templateCode, templateParam);
+            if (!SmsSendUtil.OK.equals(smsResponseResult.getCode())) {
+                throw ExceptionResultEnum.ERROR.exception("阿里云短信发送接口调用失败");
+            }
+            basicMessage.setSendStatus(smsResponseResult.getCode());
+            basicMessage.setSendResult(smsResponseResult.getMessage());
+
+        } catch (Exception e) {
+            basicMessage.setSendStatus("SYSTEM_ERROR");
+            basicMessage.setSendResult(e.getMessage());
+        } finally {
+            basicMessage.setId(SystemConstant.getDbUuid());
+            basicMessage.setSchoolId(schoolId);
+            basicMessage.setUserId(userId);
+            basicMessage.setUserName(userName);
+            basicMessage.setMobileNumber(mobileNumber);
+            basicMessage.setTemplateCode(templateCode);
+            basicMessage.setVariableParams(variableParams);
+            basicMessage.setMessageType(messageType);
+            basicMessage.setBusinessOperate(messageType.getName());
+            basicMessage.setResendCount(0);
+            basicMessage.setCreateTime(System.currentTimeMillis());
+            this.save(basicMessage);
+        }
+    }
+
     /**
      * 失败重发
      *

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

@@ -894,21 +894,6 @@ public class ExamTaskServiceImpl extends ServiceImpl<ExamTaskMapper, ExamTask> i
             examTaskDetail.setUnexposedPaperType(examTaskDetail.getPaperType());
             examTaskDetail.setExamTaskId(examTask.getId());
             examTaskDetail.insertInfo(sysUser.getId());
-            List<PaperInfoVo> filePathVoList = examTaskDetail.getPaperInfoVoList();
-            for (PaperInfoVo paperInfoVo : filePathVoList) {
-                BasicAttachment basicAttachment = basicAttachmentService.getById(paperInfoVo.getAttachmentId());
-                if (basicAttachment != null) {
-                    FilePathVo filePathVo = JSON.parseObject(basicAttachment.getPath(), FilePathVo.class);
-                    InputStream inputStream = fileUploadService.downloadFile(filePathVo.getPath(), filePathVo.getUploadType(), filePathVo.getType());
-                    List<ConvertJpgStorage> convertJpgStorageList = htmlToJpgUtil.convertPdfToJpg(Long.valueOf(paperInfoVo.getAttachmentId()), inputStream, sysUser.getId());
-                    if (convertJpgStorageList.size() > 0) {
-                        paperInfoVo.setJpgAttachmentId(JSON.toJSONString(convertJpgStorageList));
-                    } else {
-                        paperInfoVo.setJpgAttachmentId(null);
-                    }
-                }
-            }
-            examTaskDetail.setPaperAttachmentIds(JSON.toJSONString(filePathVoList));
             examTaskDetailService.save(examTaskDetail);
 
             String paperAttachmentIds = examTaskDetail.getPaperAttachmentIds();
@@ -1297,19 +1282,6 @@ public class ExamTaskServiceImpl extends ServiceImpl<ExamTaskMapper, ExamTask> i
                 examTaskDetail.setUnexposedPaperType(examTaskDetail.getPaperType());
                 examTaskDetail.setExamTaskId(examTask.getId());
                 examTaskDetail.insertInfo(sysUser.getId());
-                List<PaperInfoVo> filePathVoList = examTaskDetail.getPaperInfoVoList();
-                for (PaperInfoVo paperInfoVo : filePathVoList) {
-                    BasicAttachment basicAttachment = basicAttachmentService.getById(paperInfoVo.getAttachmentId());
-                    FilePathVo filePathVo = JSON.parseObject(basicAttachment.getPath(), FilePathVo.class);
-                    InputStream inputStream = fileUploadService.downloadFile(filePathVo.getPath(), filePathVo.getUploadType(), filePathVo.getType());
-                    List<ConvertJpgStorage> convertJpgStorageList = htmlToJpgUtil.convertPdfToJpg(Long.valueOf(paperInfoVo.getAttachmentId()), inputStream, sysUser.getId());
-                    if (convertJpgStorageList.size() > 0) {
-                        paperInfoVo.setJpgAttachmentId(JSON.toJSONString(convertJpgStorageList));
-                    } else {
-                        paperInfoVo.setJpgAttachmentId(null);
-                    }
-                }
-                examTaskDetail.setPaperAttachmentIds(JSON.toJSONString(filePathVoList));
                 examTaskDetailService.save(examTaskDetail);
 
                 String paperAttachmentIds = examTaskDetail.getPaperAttachmentIds();
@@ -2367,8 +2339,7 @@ public class ExamTaskServiceImpl extends ServiceImpl<ExamTaskMapper, ExamTask> i
                 taskQueryWrapper.lambda().eq(ExamTask::getSchoolId, schoolId).eq(ExamTask::getExamId, examId).eq(ExamTask::getPaperNumber, examTask.getPaperNumber());
                 ExamTask task = this.getOne(taskQueryWrapper);
                 if (task != null) {
-                    BasicExam basicExam = basicExamService.getById(examId);
-                    throw ExceptionResultEnum.ERROR.exception("试卷编号[" + examTask.getPaperNumber() + "]在考试[" + basicExam.getName() + "]下已存在");
+                    return;
                 }
             } else {
                 examTask.setPaperNumber(printCommonService.autoCreatePaperNumber(examId));
@@ -2386,6 +2357,9 @@ public class ExamTaskServiceImpl extends ServiceImpl<ExamTaskMapper, ExamTask> i
                         TFCustomTypeEnum.ELECTRON_FLOW,
                         examTask.getUserId(),
                         true);
+                map.put("userId", examTask.getUserId());
+                map.put("schoolId", schoolId);
+                map.put("orgId", examTask.getTeachingRoomId());
                 map = activitiService.customFlowStart(map);
                 examTask.setFlowId(SystemConstant.convertIdToLong((String) map.get(SystemConstant.FLOW_ID)));
                 map.computeIfAbsent(SystemConstant.FLOW_JOIN_TYPE, v -> FlowJoinTypeEnum.NEW);
@@ -2393,7 +2367,6 @@ public class ExamTaskServiceImpl extends ServiceImpl<ExamTaskMapper, ExamTask> i
             } else if (Objects.nonNull(examTask.getReview()) && !examTask.getReview()) {
                 examTask.setStatus(ExamStatusEnum.STAGE);
             }
-            examTask.setSource(ExamTaskSourceEnum.ASSIGN);
             this.save(examTask);
         } catch (Exception e) {
             log.error(SystemConstant.LOG_ERROR, e);

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

@@ -44,7 +44,11 @@ public class TFFlowJoinServiceImpl extends ServiceImpl<TFFlowJoinMapper, TFFlowJ
      */
     @Override
     public boolean saveOrUpdate(Map<String, Object> map) {
-        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
+        Long userId = map.containsKey("userId") ? Long.valueOf(map.get("userId").toString()) : null;
+        if(userId == null){
+            SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
+            userId = sysUser.getId();
+        }
         Long objectId = (Long) map.get(SystemConstant.OBJECT_ID);
         Long flowId = SystemConstant.convertIdToLong((String) map.get(SystemConstant.FLOW_ID));
         Long flowEntityId = SystemConstant.convertIdToLong((String) map.get(SystemConstant.FLOW_ENTITY_ID));
@@ -61,16 +65,16 @@ public class TFFlowJoinServiceImpl extends ServiceImpl<TFFlowJoinMapper, TFFlowJ
             tfFlowJoinQueryWrapper.lambda().eq(TFFlowJoin::getObjectId, objectId).orderByAsc(TFFlowJoin::getCreateTime);
             List<TFFlowJoin> tfFlowJoinList = this.list(tfFlowJoinQueryWrapper);
             if (Objects.isNull(tfFlowJoinList) || tfFlowJoinList.size() == 0) {
-                TFFlowJoin tfFlowJoin = new TFFlowJoin(flowEntityId, objectId, flowId, 1, flowJoinTypeEnum, sysUser.getId(), flowType.getTable());
+                TFFlowJoin tfFlowJoin = new TFFlowJoin(flowEntityId, objectId, flowId, 1, flowJoinTypeEnum, userId, flowType.getTable());
                 this.save(tfFlowJoin);
             } else if (Objects.nonNull(tfFlowJoinList) && tfFlowJoinList.size() >= 1) {
                 if (flowJoinTypeEnum == FlowJoinTypeEnum.NEW) {//子流程
                     TFFlowJoin tfFlowJoin = tfFlowJoinList.get(0);
                     Integer level = tfFlowJoin.getLevel();
-                    TFFlowJoin tfFlowJoinSub = new TFFlowJoin(flowEntityId, objectId, flowId, ++level, flowJoinTypeEnum, sysUser.getId(), flowType.getTable());
+                    TFFlowJoin tfFlowJoinSub = new TFFlowJoin(flowEntityId, objectId, flowId, ++level, flowJoinTypeEnum, userId, flowType.getTable());
                     this.save(tfFlowJoinSub);
                 } else {//否则是重启流程
-                    TFFlowJoin tfFlowJoin = new TFFlowJoin(flowEntityId, objectId, flowId, 1, flowJoinTypeEnum, sysUser.getId(), flowType.getTable());
+                    TFFlowJoin tfFlowJoin = new TFFlowJoin(flowEntityId, objectId, flowId, 1, flowJoinTypeEnum, userId, flowType.getTable());
                     this.save(tfFlowJoin);
                 }
             }

+ 10 - 0
distributed-print-business/src/main/resources/mapper/BasicExamMapper.xml

@@ -57,4 +57,14 @@
         </where>
         order by a.create_time desc
     </select>
+    <select id="listSyncData" resultType="com.qmth.teachcloud.common.bean.dto.TSyncDataDto">
+        SELECT
+            tsd.*
+        FROM
+            t_sync_data tsd
+                LEFT JOIN
+            basic_exam be ON tsd.exam_id = be.id
+        WHERE
+            be.enable = TRUE
+    </select>
 </mapper>

+ 39 - 1
distributed-print/install/mysql/upgrade/3.4.3.sql

@@ -26,6 +26,7 @@ CREATE TABLE `t_sync_data` (
     COMMENT = '数据同步设置';
 
 CREATE TABLE `t_sync_data_log` (
+      `id` BIGINT(20) NOT NULL,
       `school_id` BIGINT(20) NOT NULL COMMENT '学校ID',
       `exam_id` BIGINT(20) NOT NULL COMMENT '考试ID',
       `data_type` VARCHAR(45) NOT NULL COMMENT '同步数据类型',
@@ -33,5 +34,42 @@ CREATE TABLE `t_sync_data_log` (
       `end_time` BIGINT(20) NULL COMMENT '结束同步时间',
       `count` INT NULL COMMENT '同步数量',
       `error_msg` MEDIUMTEXT NULL COMMENT '失败原因',
-      PRIMARY KEY (`school_id`, `exam_id`, `data_type`))
+      PRIMARY KEY (`id`))
     COMMENT = '数据同步日志';
+
+CREATE TABLE `t_sync_data_student`  (
+        `id` bigint NOT NULL COMMENT 'id',
+        `school_id` bigint NOT NULL COMMENT '学校id',
+        `exam_id` bigint NOT NULL COMMENT '考试id',
+        `course_code` varchar(100) NULL DEFAULT NULL COMMENT '课程编号',
+        `course_name` varchar(200) NULL DEFAULT NULL COMMENT '课程名称',
+        `course_college_name` varchar(200) NULL DEFAULT NULL COMMENT '课程开课学院',
+        `paper_number` varchar(100) NULL DEFAULT NULL COMMENT '试卷编号',
+        `student_name` varchar(50) NOT NULL COMMENT '姓名',
+        `student_code` varchar(50) NOT NULL COMMENT '学号',
+        `site_number` varchar(10) NULL DEFAULT NULL COMMENT '座位号',
+        `student_college_name` varchar(100) NULL DEFAULT NULL COMMENT '学院',
+        `major_name` varchar(100) NULL DEFAULT NULL COMMENT '专业',
+        `teach_class_name` varchar(100) NULL DEFAULT NULL,
+        `class_name` varchar(100) NULL DEFAULT NULL,
+        `exam_start_time` bigint NULL DEFAULT NULL COMMENT '考试开始时间',
+        `exam_end_time` bigint NULL DEFAULT NULL COMMENT '考试结束时间',
+        `exam_place` varchar(50) NULL DEFAULT NULL COMMENT '考点',
+        `exam_room` varchar(50) NULL DEFAULT NULL COMMENT '考场',
+        `teacher_code` varchar(50) NULL COMMENT '命题老师工号',
+        `teacher_name` varchar(50) NULL COMMENT '命题老师姓名',
+        `update_status` TINYINT(1) NULL DEFAULT 0 COMMENT '是否已同步到考生表中',
+        PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '数据同步考生' ROW_FORMAT = Dynamic;
+
+ALTER TABLE `basic_message`
+    CHANGE COLUMN `user_id` `user_id` BIGINT NULL COMMENT '消息接收人用户' ,
+    CHANGE COLUMN `mobile_number` `mobile_number` VARCHAR(11) CHARACTER SET 'utf8mb4' NOT NULL COMMENT '电话号码' ;
+
+ALTER TABLE `basic_message`
+    CHANGE COLUMN `template_code` `template_code` VARCHAR(45) CHARACTER SET 'utf8mb4' NULL COMMENT '消息模板代码' ;
+
+INSERT INTO `sys_config` (`id`, `config_key`, `config_name`, `config_value`, `enable`, `sort`, `create_id`, `create_time`, `update_time`) VALUES ('50', 'sms.sync.data.code', '数据同步失败通知', 'SMS_475870952', '1', '19', '1', '1733878447209', '1733878447249');
+
+ALTER TABLE `basic_message`
+    CHANGE COLUMN `send_result` `send_result` VARCHAR(2000) CHARACTER SET 'utf8mb4' NULL DEFAULT NULL COMMENT '消息发送结果' ;

+ 6 - 5
distributed-print/src/main/java/com/qmth/distributed/print/api/SysController.java

@@ -163,7 +163,7 @@ public class SysController {
                 throw ExceptionResultEnum.ERROR.exception("用户被禁用");
             }
 
-            String decodePassword =  Base64Util.encode(AesECBUtil.decryptSimple(password).getBytes());
+            String decodePassword = Base64Util.encode(AesECBUtil.decryptSimple(password).getBytes());
             if (!decodePassword.equals(userList.get(0).getPassword())) {
                 throw ExceptionResultEnum.ERROR.exception("用户名或密码错误");
             }
@@ -426,7 +426,8 @@ public class SysController {
             BasicSchool basicSchool = null;
             if (StringUtils.isNotBlank(code)) {
                 basicSchool = commonCacheService.schoolCache(code);
-            } else {
+            }
+            if (basicSchool == null) {
                 List<BasicSchool> basicSchoolList = basicSchoolService.listByDefaultSchool(true);
                 if (CollectionUtils.isNotEmpty(basicSchoolList)) {
                     basicSchool = basicSchoolList.get(0);
@@ -454,7 +455,7 @@ public class SysController {
             map.put("schoolCode", code);
             // 广药命题界面提示信息
             map.put("examTaskInstr", basicSchool.getExamTaskInstr());
-            map.put("cardSize",Objects.nonNull(cardSize) ? Arrays.asList(
+            map.put("cardSize", Objects.nonNull(cardSize) ? Arrays.asList(
                     cardSize.getConfigValue().replaceAll("\\[", "").replaceAll("\\]", "").split(", ")) : null);
         } else {
             SysConfig sysConfig = commonCacheService.addSysConfigCache(SystemConstant.ADMIN_LOGO_URL);
@@ -641,8 +642,8 @@ public class SysController {
     @ApiResponses({@ApiResponse(code = 200, message = "返回信息", response = EditResult.class)})
     @Aac(auth = false)
     public void filePreview(@ApiParam(value = "附件id", defaultValue = "") @RequestParam(value = "id", required = false) Long id,
-                              HttpServletResponse response) {
-        if(id == null){
+                            HttpServletResponse response) {
+        if (id == null) {
             throw ExceptionResultEnum.ERROR.exception("请求参数有误");
         }
 

+ 39 - 7
distributed-print/src/main/java/com/qmth/distributed/print/api/admin/DataController.java

@@ -3,27 +3,32 @@ package com.qmth.distributed.print.api.admin;
 import com.qmth.boot.api.annotation.Aac;
 import com.qmth.boot.api.constant.ApiConstant;
 import com.qmth.distributed.print.business.bean.params.SysAdminSetParam;
-import com.qmth.distributed.print.business.service.ClientUpgradeService;
+import com.qmth.distributed.print.business.service.BasicExamService;
 import com.qmth.teachcloud.common.contant.SystemConstant;
-import com.qmth.teachcloud.common.enums.ClientUpgradeToolTypeEnum;
+import com.qmth.teachcloud.common.entity.BasicExam;
 import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
-import com.qmth.teachcloud.common.enums.clientpackage.ClientPackageEnum;
 import com.qmth.teachcloud.common.util.Result;
 import com.qmth.teachcloud.common.util.ResultUtil;
 import com.qmth.teachcloud.data.entity.TSyncData;
 import com.qmth.teachcloud.data.service.DataService;
 import com.qmth.teachcloud.data.service.TSyncDataService;
+import com.qmth.teachcloud.task.enums.JobEnum;
+import com.qmth.teachcloud.task.job.DataSyncJob;
+import com.qmth.teachcloud.task.service.QuartzService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.Scope;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.validation.BindingResult;
 import org.springframework.web.bind.annotation.*;
-import org.springframework.web.multipart.MultipartFile;
 
 import javax.annotation.Resource;
 import javax.validation.Valid;
 import javax.validation.constraints.Max;
 import javax.validation.constraints.Min;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.Optional;
 
 /**
@@ -35,6 +40,10 @@ import java.util.Optional;
 @Aac(auth = false)
 public class DataController {
 
+    @Resource
+    private BasicExamService basicExamService;
+    @Resource
+    private QuartzService quartzService;
     @Resource
     private DataService dataService;
     @Resource
@@ -62,14 +71,19 @@ public class DataController {
     @ApiOperation(value = "新增/修改同步任务")
     @RequestMapping(value = "/param/save", method = RequestMethod.POST)
     public Result paramSave(@ApiParam(value = "任务对象") @RequestBody TSyncData tSyncData) {
-        return ResultUtil.ok(tSyncDataService.saveData(tSyncData));
+        TSyncData saveData = tSyncDataService.saveData(tSyncData);
+        if (saveData != null) {
+            quartzTask(saveData);
+        }
+        return ResultUtil.ok(true);
     }
 
     @ApiOperation(value = "手动同步")
     @RequestMapping(value = "/start/sync", method = RequestMethod.POST)
     public Result startSync(@ApiParam(value = "学校ID") @RequestParam(value = "schoolId") Long schoolId,
                             @ApiParam(value = "考试ID") @RequestParam(value = "examId") Long examId) {
-        return ResultUtil.ok(tSyncDataService.syncData(schoolId, examId));
+        quartzService.runAJobNow(JobEnum.DATA_SYNC.name() + "-" + schoolId + "-" + examId, JobEnum.DATA_SYNC.getGroupName());
+        return ResultUtil.ok(true);
     }
 
     @ApiOperation(value = "查看日志")
@@ -84,8 +98,26 @@ public class DataController {
     @ApiOperation(value = "启用/禁用")
     @RequestMapping(value = "/enable/sync", method = RequestMethod.POST)
     public Result enable(@RequestBody TSyncData tSyncData) {
-        return ResultUtil.ok(tSyncDataService.enable(tSyncData));
+        if (tSyncDataService.enable(tSyncData)) {
+            quartzTask(tSyncDataService.selectByMultiId(tSyncData));
+        }
+        return ResultUtil.ok(true);
     }
 
+
+    private void quartzTask(TSyncData syncData) {
+        Long startTime = syncData.getStartTime();
+        Long endTime = syncData.getEndTime();
+        BasicExam basicExam = basicExamService.getById(syncData.getExamId());
+        // 考试已禁用、任务已禁用、未到开始时间、超过结束时间,未设置执行时间 。不执行
+        quartzService.deleteJob(JobEnum.DATA_SYNC.name() + "-" + syncData.getSchoolId() + "-" + syncData.getExamId(), JobEnum.DATA_SYNC.getGroupName());
+        long currentTime = System.currentTimeMillis();
+        if (!basicExam.getEnable() || !syncData.getEnable() || currentTime < startTime || currentTime > endTime || StringUtils.isBlank(syncData.getCron())) {
+            return;
+        }
+        Map expireJobMap = new HashMap();
+        expireJobMap.computeIfAbsent("name", v -> DataSyncJob.class.getName());
+        quartzService.addJob(DataSyncJob.class, JobEnum.DATA_SYNC.name() + "-" + syncData.getSchoolId() + "-" + syncData.getExamId(), JobEnum.DATA_SYNC.getGroupName(), syncData.getCron(), expireJobMap);
+    }
 }
 

+ 8 - 11
distributed-print/src/main/java/com/qmth/distributed/print/start/StartRunning.java

@@ -1,11 +1,10 @@
 package com.qmth.distributed.print.start;
 
 import com.qmth.distributed.print.business.service.BasicExamService;
+import com.qmth.teachcloud.common.bean.dto.TSyncDataDto;
 import com.qmth.teachcloud.common.entity.BasicExam;
 import com.qmth.teachcloud.common.service.AuthInfoService;
 import com.qmth.teachcloud.common.service.SysConfigService;
-import com.qmth.teachcloud.data.entity.TSyncData;
-import com.qmth.teachcloud.data.service.TSyncDataService;
 import com.qmth.teachcloud.task.enums.JobEnum;
 import com.qmth.teachcloud.task.job.*;
 import com.qmth.teachcloud.task.job.service.JobService;
@@ -41,8 +40,6 @@ public class StartRunning implements CommandLineRunner {
     @Resource
     private JobService jobService;
     @Resource
-    private TSyncDataService tSyncDataService;
-    @Resource
     private BasicExamService basicExamService;
 
     @Override
@@ -141,7 +138,7 @@ public class StartRunning implements CommandLineRunner {
         log.info("服务器启动时执行,PDF生成定时任务 end");
 
         // 数据同步
-//        dataSync();
+        dataSync();
 
         log.info("服务器启动时执行 end");
     }
@@ -149,20 +146,20 @@ public class StartRunning implements CommandLineRunner {
     private void dataSync() {
         log.info("服务器启动时执行,数据同步定时任务 start");
         long currentTime = System.currentTimeMillis();
-        List<TSyncData> tSyncDataList = tSyncDataService.list();
+        List<TSyncDataDto> tSyncDataList = basicExamService.listSyncData();
 
         Map expireJobMap = new HashMap();
         expireJobMap.computeIfAbsent("name", v -> DataSyncJob.class.getName());
-        for (TSyncData syncData : tSyncDataList) {
+        for (TSyncDataDto syncData : tSyncDataList) {
             Long startTime = syncData.getStartTime();
             Long endTime = syncData.getEndTime();
             BasicExam basicExam = basicExamService.getById(syncData.getExamId());
-            // 考试已禁用、未到开始时间、超过结束时间,未设置执行时间 。不执行
-            quartzService.deleteJob(JobEnum.DATA_SYNC.name() + syncData.getSchoolId(), JobEnum.DATA_SYNC.getGroupName());
-            if (!basicExam.getEnable() || currentTime < startTime || currentTime > endTime || StringUtils.isBlank(syncData.getCron())) {
+            // 考试已禁用、任务已禁用、未到开始时间、超过结束时间,未设置执行时间 。不执行
+            quartzService.deleteJob(JobEnum.DATA_SYNC.name() + "-" + syncData.getSchoolId() + "-" + syncData.getExamId(), JobEnum.DATA_SYNC.getGroupName());
+            if (!basicExam.getEnable() || !syncData.getEnable() || currentTime < startTime || currentTime > endTime || StringUtils.isBlank(syncData.getCron())) {
                 continue;
             }
-            quartzService.addJob(DataSyncJob.class, JobEnum.DATA_SYNC.name() + syncData.getSchoolId(), JobEnum.DATA_SYNC.getGroupName(), syncData.getCron(), expireJobMap);
+            quartzService.addJob(DataSyncJob.class, JobEnum.DATA_SYNC.name() + "-" + syncData.getSchoolId() + "-" + syncData.getExamId(), JobEnum.DATA_SYNC.getGroupName(), syncData.getCron(), expireJobMap);
         }
         log.info("服务器启动时执行,数据同步定时任务 end");
     }

+ 1 - 1
distributed-print/src/test/java/com/qmth/distributed/print/ServiceTest.java

@@ -6,7 +6,7 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.qmth.distributed.print.business.bean.dto.StudentNumberConfigDto;
 import com.qmth.distributed.print.business.bean.dto.StudentNumberLetterRelationShipDto;
 import com.qmth.distributed.print.business.bean.dto.examObject.ExamObjectDto;
-import com.qmth.distributed.print.business.bean.params.SysAdminSetParam;
+import com.qmth.teachcloud.common.bean.params.SysAdminSetParam;
 import com.qmth.distributed.print.business.entity.ExamPrintPlan;
 import com.qmth.distributed.print.business.entity.ExamStudent;
 import com.qmth.distributed.print.business.mapper.ExamStudentMapper;

+ 121 - 0
teachcloud-common/src/main/java/com/qmth/teachcloud/common/bean/dto/TSyncDataDto.java

@@ -0,0 +1,121 @@
+package com.qmth.teachcloud.common.bean.dto;
+
+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.github.jeffreyning.mybatisplus.anno.MppMultiId;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.io.Serializable;
+
+/**
+ * <p>
+ * 数据同步设置
+ * </p>
+ *
+ * @author xf
+ * @since 2024-12-05
+ */
+public class TSyncDataDto implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @JsonSerialize(using = ToStringSerializer.class)
+    private Long schoolId;
+
+    @ApiModelProperty(value = "学期ID")
+    @JsonSerialize(using = ToStringSerializer.class)
+    private Long semesterId;
+
+    @ApiModelProperty(value = "考试ID")
+    @JsonSerialize(using = ToStringSerializer.class)
+    private Long examId;
+
+    @ApiModelProperty(value = "同步开始时间")
+    private Long startTime;
+
+    @ApiModelProperty(value = "同步结束时间")
+    private Long endTime;
+
+    @ApiModelProperty(value = "状态(0:未同步/已完成,1:同步中)")
+    private Boolean status;
+
+    @ApiModelProperty(value = "cron表达式")
+    private String cron;
+
+    @ApiModelProperty(value = "启用/禁用")
+    private Boolean enable;
+
+    @ApiModelProperty(value = "考试启用/禁用")
+    private Boolean examEnable;
+
+    public Long getSchoolId() {
+        return schoolId;
+    }
+
+    public void setSchoolId(Long schoolId) {
+        this.schoolId = schoolId;
+    }
+    public Long getSemesterId() {
+        return semesterId;
+    }
+
+    public void setSemesterId(Long semesterId) {
+        this.semesterId = semesterId;
+    }
+    public Long getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Long examId) {
+        this.examId = examId;
+    }
+
+    public Long getStartTime() {
+        return startTime;
+    }
+
+    public void setStartTime(Long startTime) {
+        this.startTime = startTime;
+    }
+    public Long getEndTime() {
+        return endTime;
+    }
+
+    public void setEndTime(Long endTime) {
+        this.endTime = endTime;
+    }
+    public Boolean getStatus() {
+        return status;
+    }
+
+    public void setStatus(Boolean status) {
+        this.status = status;
+    }
+
+    public String getCron() {
+        return cron;
+    }
+
+    public void setCron(String cron) {
+        this.cron = cron;
+    }
+
+    public Boolean getEnable() {
+        return enable;
+    }
+
+    public void setEnable(Boolean enable) {
+        this.enable = enable;
+    }
+
+    public Boolean getExamEnable() {
+        return examEnable;
+    }
+
+    public void setExamEnable(Boolean examEnable) {
+        this.examEnable = examEnable;
+    }
+}

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

@@ -214,6 +214,7 @@ public class SystemConstant {
     public static final String SMS_AUDIT_REJECT_CODE = "sms.audit.reject.code";
     public static final String SMS_UPLOAD_STRUCTURE_CODE = "sms.upload.structure.code";
     public static final String SMS_AUDIT_COPY_USER_CODE = "sms.audit.copy.user.code";
+    public static final String SMS_SYNC_DATA_CODE = "sms.sync.data.code";
 
     /**
      * 系统学校配置

+ 2 - 1
teachcloud-common/src/main/java/com/qmth/teachcloud/common/enums/MessageEnum.java

@@ -46,7 +46,8 @@ public enum MessageEnum {
     /**
      * 审核抄送
      */
-    NOTICE_OF_AUDIT_COPY_USER("审核抄送生成通知","${userName}您好,${courseName}相关命题任务已经提交,由${auditUserNames}负责审核,请您查看!");
+    NOTICE_OF_AUDIT_COPY_USER("审核抄送生成通知","${userName}您好,${courseName}相关命题任务已经提交,由${auditUserNames}负责审核,请您查看!"),
+    NOTICE_SYNC_DATA("数据同步失败通知","管理员好,${schoolName}学校,数据同步失败,请尽快检查");
 
     MessageEnum(String name, String template) {
         this.name = name;

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

@@ -374,7 +374,8 @@ public class BasicCourseServiceImpl extends ServiceImpl<BasicCourseMapper, Basic
             basicCourse.setSchoolId(schoolId);
             basicCourse.setCode(courseDataVo.getCode());
             basicCourse.setName(courseDataVo.getName());
-            basicCourse.setCollegeName(courseDataVo.getCollegeName());
+            basicCourse.setTeachingRoomId(sysOrg.getId());
+            basicCourse.setEnable(true);
             basicCourse.setCreateTime(System.currentTimeMillis());
             this.save(basicCourse);
         }

+ 4 - 0
teachcloud-common/src/main/java/com/qmth/teachcloud/common/service/impl/SysOrgServiceImpl.java

@@ -592,8 +592,12 @@ public class SysOrgServiceImpl extends ServiceImpl<SysOrgMapper, SysOrg> impleme
         SysOrg rootOrg = this.findRootOrg(schoolId);
         SysOrg org = this.findByParentIdAndName(rootOrg.getId(), orgDataVo.getCollegeName());
         if (org == null) {
+            org = new SysOrg();
             org.setId(SystemConstant.getDbUuid());
+            org.setSchoolId(schoolId);
+            org.setName(orgDataVo.getCollegeName());
             org.setParentId(rootOrg.getId());
+            org.setEnable(true);
             this.save(org);
         }
     }

+ 64 - 0
teachcloud-common/src/main/java/com/qmth/teachcloud/common/service/impl/SysUserServiceImpl.java

@@ -1173,7 +1173,71 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
 
     @Override
     public void saveUserFromSync(Long schoolId, UserDataVo userDataVo) {
+        try {
+            // 工号检验
+            SysUser sysUser = this.getByLoginName(schoolId, userDataVo.getCode());
+
+            SysOrg rootOrg = sysOrgService.findRootOrg(schoolId);
+            SysOrg org = sysOrgService.findByParentIdAndName(rootOrg.getId(), userDataVo.getCollegeName());
+            if (org == null) {
+                org = new SysOrg();
+                org.setId(SystemConstant.getDbUuid());
+                org.setSchoolId(schoolId);
+                org.setName(userDataVo.getCollegeName());
+                org.setParentId(rootOrg.getId());
+                org.setEnable(true);
+                sysOrgService.save(org);
+            }
+
+            if (sysUser == null) {
+                sysUser = new SysUser();
+                BasicSchool basicSchool = commonCacheService.schoolCache(schoolId);
+                String password = StringUtils.isNoneBlank(basicSchool.getInitPassword()) ? basicSchool.getInitPassword() : Base64Util.encode(SystemConstant.INIT_PASSWORD.getBytes());
+                sysUser.setId(SystemConstant.getDbUuid());
+                sysUser.setSchoolId(schoolId);
+                sysUser.setLoginName(userDataVo.getCode());
+                sysUser.setRealName(userDataVo.getName());
+                sysUser.setCode(userDataVo.getCode());
+                sysUser.setPassword(password);
+                sysUser.setMobileNumber(userDataVo.getPhoneNumber());
+                sysUser.setOrgId(org.getId());
+                sysUser.setEnable(true);
+                sysUser.setPwdCount(0);
+                sysUserService.save(sysUser);
+
+                SysRole sysRole = sysRoleService.getDefaultRoleByType(RoleTypeEnum.SCHOOL_TEACHER);
+                Long[] roleIds = new Long[]{sysRole.getId()};
+                commonService.addUserRolePrivilege(sysUser, roleIds);
+            } else {
+                sysUserService.update(new UpdateWrapper<SysUser>().lambda()
+                        .eq(SysUser::getId, sysUser.getId())
+                        .set(SysUser::getRealName, userDataVo.getName())
+                        .set(SysUser::getMobileNumber, userDataVo.getPhoneNumber())
+                        .set(SysUser::getOrgId, org.getId())
+                        .set(SysUser::getUpdateTime, System.currentTimeMillis()));
 
+                //如果修改了机构或手机号,需更新用户缓存
+                if (sysUser.getOrgId().longValue() != org.getId().longValue()
+                        || !Objects.equals(sysUser.getMobileNumber(), userDataVo.getPhoneNumber())) {
+                    commonCacheService.updateUserCache(sysUser.getId());
+                    commonCacheService.updateUserAuthCache(sysUser.getId());
+                }
+            }
+        } catch (Exception e) {
+            log.error(SystemConstant.LOG_ERROR, e);
+            if (e instanceof DuplicateKeyException) {
+                String errorColumn = e.getCause().toString();
+                String columnStr = errorColumn.substring(errorColumn.lastIndexOf("key") + 3).replaceAll("'", "");
+                throw ExceptionResultEnum.SQL_ERROR.exception("[" + FieldUniqueEnum.convertToTitle(columnStr) + "]数据不允许重复插入");
+            } else if (e instanceof DataIntegrityViolationException || e instanceof BadSqlGrammarException) {
+                String content = JdbcErrorUtil.parseErrorMsg(e.getMessage().toString());
+                throw ExceptionResultEnum.SQL_ERROR.exception(content);
+            } else if (e instanceof ApiException) {
+                ResultUtil.error((ApiException) e, ((ApiException) e).getCode(), e.getMessage());
+            } else {
+                ResultUtil.error(e.getMessage());
+            }
+        }
     }
 
     @Override

+ 47 - 0
teachcloud-common/src/main/java/com/qmth/teachcloud/common/util/SmsSendUtil.java

@@ -2,11 +2,13 @@ package com.qmth.teachcloud.common.util;
 
 import com.alibaba.fastjson.JSONObject;
 import com.qmth.boot.api.exception.ApiException;
+import com.qmth.boot.core.retrofit.utils.SignatureInfo;
 import com.qmth.boot.core.sms.model.SmsSendRequest;
 import com.qmth.boot.core.sms.model.SmsSendResponse;
 import com.qmth.boot.core.sms.service.SmsService;
 import com.qmth.teachcloud.common.bean.result.SmsResponseResult;
 import com.qmth.teachcloud.common.contant.SystemConstant;
+import com.qmth.teachcloud.common.entity.BasicSchool;
 import com.qmth.teachcloud.common.entity.SysConfig;
 import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
 import com.qmth.teachcloud.common.enums.MessageEnum;
@@ -76,6 +78,47 @@ public class SmsSendUtil {
         return smsResponseResult;
     }
 
+    /**
+     * 离线激活短信发送
+     *
+     * @param schoolId      学校ID
+     * @param phoneNumber   发送手机号
+     * @param configKey     参数key
+     * @param templateParam 模版变量
+     * @return bizId 本次操作业务标识
+     */
+    public SmsResponseResult sendSms(Long schoolId, String phoneNumber, String configKey, Map<String, Object> templateParam) {
+        validPhoneNumber(phoneNumber);
+        SmsSendRequest smsSendRequest = new SmsSendRequest();
+        // 必填,发送手机号
+        smsSendRequest.setPhoneNumber(phoneNumber);
+        // 必填,短信签名
+        String signName = getConfigValue(SystemConstant.SMS_SIGN_NAME);
+        smsSendRequest.setSignName(signName);
+        // 必填,短信模版编号
+        String templateCode = getConfigValue(configKey);
+        smsSendRequest.setTemplateCode(templateCode);
+        //模版变量,可选
+        if (templateParam != null && !templateParam.isEmpty()) {
+            smsSendRequest.setTemplateParam(templateParam);
+        }
+        SmsResponseResult smsResponseResult = new SmsResponseResult();
+        try {
+            BasicSchool basicSchool = commonCacheService.schoolCache(schoolId);
+            SignatureInfo signatureInfo = SignatureInfo.secret(basicSchool.getAccessKey(), basicSchool.getAccessSecret());
+            SmsSendResponse smsSendResponse = smsService.sendSms(signatureInfo, smsSendRequest);
+            if (smsSendResponse == null) {
+                throw ExceptionResultEnum.ERROR.exception("短信发送失败");
+            }
+            smsResponseResult.setCode(OK);
+            smsResponseResult.setMessage(smsSendResponse.getBizId());
+        } catch (ApiException e) {
+            smsResponseResult.setCode(ERROR);
+            smsResponseResult.setMessage(e.getMessage());
+        }
+        return smsResponseResult;
+    }
+
     /**
      * 校验手机号
      *
@@ -170,6 +213,10 @@ public class SmsSendUtil {
                 templateCode = SystemConstant.SMS_AUDIT_COPY_USER_CODE;
                 templateContent = messageEnum.getTemplate();
                 break;
+            case NOTICE_SYNC_DATA:
+                templateCode = SystemConstant.SMS_SYNC_DATA_CODE;
+                templateContent = messageEnum.getTemplate();
+                break;
             default:
                 break;
         }

+ 1 - 1
teachcloud-common/src/main/resources/mapper/BasicCourseMapper.xml

@@ -90,7 +90,7 @@
                     AND bc.create_id = #{dpr.requestUserId}
                 </if>
                 <if test="dpr.orgIdSet != null and dpr.orgIdSet != '' and dpr.orgIdSet.size > 0">
-                    AND bc.org_id IN
+                    AND bc.teaching_room_id IN
                     <foreach collection="dpr.orgIdSet" item="item" index="index" open="(" separator="," close=")">
                         #{item}
                     </foreach>

+ 9 - 1
teachcloud-data/pom.xml

@@ -34,6 +34,10 @@
             <groupId>com.qmth.distributed.print.business</groupId>
             <artifactId>distributed-print-business</artifactId>
         </dependency>
+        <dependency>
+            <groupId>com.qmth.boot</groupId>
+            <artifactId>core-sms</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.jetbrains</groupId>
             <artifactId>annotations</artifactId>
@@ -52,7 +56,11 @@
             <artifactId>commons-dbutils</artifactId>
             <version>1.8.1</version>
         </dependency>
-
+        <dependency>
+            <groupId>com.oracle.database.jdbc</groupId>
+            <artifactId>ojdbc8</artifactId>
+            <version>23.6.0.24.10</version>
+        </dependency>
     </dependencies>
 
 </project>

+ 107 - 102
teachcloud-data/src/main/java/com/qmth/teachcloud/data/DataUtil.java

@@ -6,53 +6,89 @@ import com.qmth.teachcloud.common.contant.SystemConstant;
 import com.qmth.teachcloud.common.entity.SysConfig;
 import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
 import com.qmth.teachcloud.common.service.CommonCacheService;
+import com.qmth.teachcloud.common.bean.sync.TSyncDataStudent;
+import com.qmth.teachcloud.data.enums.DataType;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
 import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.jdbc.datasource.DriverManagerDataSource;
 import org.springframework.stereotype.Component;
 
 import javax.annotation.Resource;
 import javax.sql.DataSource;
-import java.sql.Connection;
-import java.sql.DriverManager;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
 @Component
 public class DataUtil {
 
     // 一页1000条
-    private static int PAGE_SIZE = 1000;
+    private static int PAGE_SIZE = 2;
 
     @Resource
     private CommonCacheService commonCacheService;
 
-    public List<OrgDataVo> listOrg(JdbcTemplate jdbcTemplate) {
-        //sql语句
-        String sql = "select * from sys_user";
+    public List<OrgDataVo> listOrg(JdbcTemplate jdbcTemplate, DataType dataType, String datasourceType) {
+
+        String sql;
+        if ("ORACLE".equals(datasourceType.trim())) {
+            sql = getOracleSql(dataType, false);
+        } else if ("MYSQL".equals(datasourceType.trim())) {
+            sql = getMysqlSql(dataType, false);
+        } else {
+            throw ExceptionResultEnum.ERROR.exception("只支持Oracle和Mysql数据库");
+        }
         return query(jdbcTemplate, sql, OrgDataVo.class);
     }
 
-    public List<UserDataVo> listUser(JdbcTemplate jdbcTemplate) {
-        //sql语句
-        String sql = "select * from sys_user limit ? ?";
-        return page(jdbcTemplate, sql, UserDataVo.class);
+    public List<UserDataVo> listUser(JdbcTemplate jdbcTemplate, DataType dataType, String datasourceType) {
+        String sql;
+        if ("ORACLE".equals(datasourceType.trim())) {
+            sql = getOracleSql(dataType, true, "code");
+            return pageOracle(jdbcTemplate, sql, UserDataVo.class);
+        } else if ("MYSQL".equals(datasourceType.trim())) {
+            sql = getMysqlSql(dataType, true);
+            return pageMysql(jdbcTemplate, sql, UserDataVo.class);
+        } else {
+            throw ExceptionResultEnum.ERROR.exception("只支持Oracle和Mysql数据库");
+        }
     }
 
-    public List<CourseDataVo> listCourse(JdbcTemplate jdbcTemplate) {
-        //sql语句
-        String sql = "select * from sys_user";
+    public List<CourseDataVo> listCourse(JdbcTemplate jdbcTemplate, DataType dataType, String datasourceType) {
+        String sql;
+        if ("ORACLE".equals(datasourceType.trim())) {
+            sql = getOracleSql(dataType, false);
+        } else if ("MYSQL".equals(datasourceType.trim())) {
+            sql = getMysqlSql(dataType, false);
+        } else {
+            throw ExceptionResultEnum.ERROR.exception("只支持Oracle和Mysql数据库");
+        }
         return query(jdbcTemplate, sql, CourseDataVo.class);
     }
 
-    public List<ExamTaskDataVo> listExamTask(JdbcTemplate jdbcTemplate) {
-        //sql语句
-        String sql = "select * from sys_user";
+    public List<ExamTaskDataVo> listExamTask(JdbcTemplate jdbcTemplate, DataType dataType, String datasourceType) {
+        String sql;
+        if ("ORACLE".equals(datasourceType.trim())) {
+            sql = getOracleSql(dataType, false);
+        } else if ("MYSQL".equals(datasourceType.trim())) {
+            sql = getMysqlSql(dataType, false);
+        } else {
+            throw ExceptionResultEnum.ERROR.exception("只支持Oracle和Mysql数据库");
+        }
         return query(jdbcTemplate, sql, ExamTaskDataVo.class);
+    }
 
+    public List<TSyncDataStudent> listExamStudent(JdbcTemplate jdbcTemplate, DataType dataType, String datasourceType) {
+        String sql;
+        if ("ORACLE".equals(datasourceType.trim())) {
+            sql = getOracleSql(dataType, true, "course_code", "student_code");
+            return pageOracle(jdbcTemplate, sql, TSyncDataStudent.class);
+        } else if ("MYSQL".equals(datasourceType.trim())) {
+            sql = getMysqlSql(dataType, true);
+            return pageMysql(jdbcTemplate, sql, TSyncDataStudent.class);
+        } else {
+            throw ExceptionResultEnum.ERROR.exception("只支持Oracle和Mysql数据库");
+        }
     }
 
     /**
@@ -61,12 +97,9 @@ public class DataUtil {
      * @param sql
      */
     private <T> List<T> query(JdbcTemplate jdbcTemplate, String sql, Class<T> tClass) {
-        if (sql.endsWith("limit ? ?")) {
-            throw ExceptionResultEnum.ERROR.exception("sql中设置了分页参数");
-        }
         List<T> list;
         try {
-            list = jdbcTemplate.queryForList(sql, tClass);
+            list = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(tClass));
         } catch (Exception e) {
             throw ExceptionResultEnum.ERROR.exception("查询失败:" + e.getMessage());
         }
@@ -78,10 +111,7 @@ public class DataUtil {
      *
      * @param sql
      */
-    private <T> List<T> page(JdbcTemplate jdbcTemplate, String sql, Class<T> tClass) {
-        if (!sql.endsWith("limit ? ?")) {
-            throw ExceptionResultEnum.ERROR.exception("sql中未设置分页参数");
-        }
+    private <T> List<T> pageMysql(JdbcTemplate jdbcTemplate, String sql, Class<T> tClass) {
         //将查询的语句封装到List集合中,集合中存储每一个员工实体
         List<T> listAll = new ArrayList<>();
         try {
@@ -89,7 +119,7 @@ public class DataUtil {
             int pageNumber = 0;
             do {
                 int offset = pageNumber * PAGE_SIZE + PAGE_SIZE;
-                list = jdbcTemplate.queryForList(sql, tClass, pageNumber, offset);
+                list = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(tClass), pageNumber, offset);
                 if (CollectionUtils.isNotEmpty(list)) {
                     listAll.addAll(list);
                     pageNumber++;
@@ -102,54 +132,63 @@ public class DataUtil {
     }
 
     /**
-     * 分页
+     * 分页
      *
      * @param sql
      */
-    /*private <T> List<T> query(String sql, Class<T> tClass) {
-        if (sql.endsWith("limit ? ?")) {
-            throw ExceptionResultEnum.ERROR.exception("sql中设置了分页参数");
-        }
-        //创建QueryRunner
-        QueryRunner qr = new QueryRunner(DruidJdbcUtils.getDataSource(createDataSourceMap()));
-        List<T> list;
-        try {
-            list = qr.query(sql, new BeanListHandler<>(tClass));
-        } catch (SQLException e) {
-            throw ExceptionResultEnum.ERROR.exception("查询失败:" + e.getMessage());
-        }
-        return list;
-    }
-
-    */
-
-    /**
-     * 分页
-     *//*
-    private <T> List<T> page(String sql, Class<T> tClass) {
-        if (!sql.endsWith("limit ? ?")) {
-            throw ExceptionResultEnum.ERROR.exception("sql中未设置分页参数");
-        }
-        //创建QueryRunner
-        QueryRunner qr = new QueryRunner(DruidJdbcUtils.getDataSource(createDataSourceMap()));
+    private <T> List<T> pageOracle(JdbcTemplate jdbcTemplate, String sql, Class<T> tClass) {
         //将查询的语句封装到List集合中,集合中存储每一个员工实体
         List<T> listAll = new ArrayList<>();
         try {
             List<T> list;
-            int pageNumber = 0;
+            int pageNumber = 1;
             do {
-                int offset = pageNumber * PAGE_SIZE + PAGE_SIZE;
-                list = qr.query(sql, new BeanListHandler<>(tClass), pageNumber, offset);
+                int startIndex = PAGE_SIZE * (pageNumber - 1) + 1;
+                int endIndex = pageNumber * PAGE_SIZE;
+                list = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(tClass), startIndex, endIndex);
                 if (CollectionUtils.isNotEmpty(list)) {
                     listAll.addAll(list);
                     pageNumber++;
                 }
             } while (CollectionUtils.isNotEmpty(list));
-        } catch (SQLException e) {
+        } catch (Exception e) {
             throw ExceptionResultEnum.ERROR.exception("查询失败:" + e.getMessage());
         }
         return listAll;
-    }*/
+    }
+
+    private String getMysqlSql(DataType dataType, boolean isPage) {
+        //sql语句
+        String sql;
+        if (isPage) {
+            sql = "select * from " + dataType.getTable() + " limit ? ?";
+        } else {
+            sql = "select * from " + dataType.getTable();
+        }
+        return sql;
+    }
+
+    private String getOracleSql(DataType dataType, boolean isPage, String... sortColumn) {
+        //sql语句
+        String sql;
+        if (isPage) {
+            StringJoiner stringJoiner = new StringJoiner("");
+            stringJoiner.add("SELECT *  FROM (SELECT t.*, ROW_NUMBER() OVER (ORDER BY ");
+            StringJoiner sortStr = new StringJoiner(",");
+            for (String s : sortColumn) {
+                sortStr.add("\"" + s + "\"");
+            }
+            stringJoiner.add(sortStr.toString());
+            stringJoiner.add(") AS rn FROM ");
+            stringJoiner.add("\"" + dataType.getTable() + "\"");
+            stringJoiner.add(" t)  WHERE rn BETWEEN ? AND ?");
+            sql = stringJoiner.toString();
+        } else {
+            sql = "select * from \"" + dataType.getTable() + "\"";
+        }
+        return sql;
+    }
+
     public DataSource createDataSourceMap(Long schoolId) {
         SysConfig datasourceType = commonCacheService.addSysConfigCache(schoolId, SystemConstant.DATA_DATASOURCE_TYPE);
         if (datasourceType == null || StringUtils.isBlank(datasourceType.getConfigValue())) {
@@ -205,37 +244,37 @@ public class DataUtil {
 
 
     public DataSource createDataSourceMap(List<SysConfigResult> params) {
-        SysConfigResult datasourceType = params.stream().filter(m->m.getCode().equals(SystemConstant.DATA_DATASOURCE_TYPE)).findFirst().orElse(null);
+        SysConfigResult datasourceType = params.stream().filter(m -> m.getCode().equals(SystemConstant.DATA_DATASOURCE_TYPE)).findFirst().orElse(null);
         if (datasourceType == null || StringUtils.isBlank(datasourceType.getValue().toString())) {
             throw ExceptionResultEnum.ERROR.exception("未设置数据库类型");
         }
         String type = datasourceType.getValue().toString().trim();
         // 数据库HOST
-        SysConfigResult datasourceHost = params.stream().filter(m->m.getCode().equals(SystemConstant.DATA_DATASOURCE_HOST)).findFirst().orElse(null);
+        SysConfigResult datasourceHost = params.stream().filter(m -> m.getCode().equals(SystemConstant.DATA_DATASOURCE_HOST)).findFirst().orElse(null);
         if (datasourceHost == null || StringUtils.isBlank(datasourceHost.getValue().toString())) {
             throw ExceptionResultEnum.ERROR.exception("未设置HOST");
         }
         String host = datasourceHost.getValue().toString().trim();
         // 数据库PORT
-        SysConfigResult datasourcePort = params.stream().filter(m->m.getCode().equals(SystemConstant.DATA_DATASOURCE_PORT)).findFirst().orElse(null);
+        SysConfigResult datasourcePort = params.stream().filter(m -> m.getCode().equals(SystemConstant.DATA_DATASOURCE_PORT)).findFirst().orElse(null);
         if (datasourcePort == null || StringUtils.isBlank(datasourcePort.getValue().toString())) {
             throw ExceptionResultEnum.ERROR.exception("未设置端口");
         }
         String port = datasourcePort.getValue().toString().trim();
         // 数据库DataName
-        SysConfigResult datasourceDataName = params.stream().filter(m->m.getCode().equals(SystemConstant.DATA_DATASOURCE_DATANAME)).findFirst().orElse(null);
+        SysConfigResult datasourceDataName = params.stream().filter(m -> m.getCode().equals(SystemConstant.DATA_DATASOURCE_DATANAME)).findFirst().orElse(null);
         if (datasourceDataName == null || StringUtils.isBlank(datasourceDataName.getValue().toString())) {
             throw ExceptionResultEnum.ERROR.exception("未设置数据库名");
         }
         String dataName = datasourceDataName.getValue().toString().trim();
         // 数据库用户名
-        SysConfigResult datasourceUserName = params.stream().filter(m->m.getCode().equals(SystemConstant.DATA_DATASOURCE_USERNAME)).findFirst().orElse(null);
+        SysConfigResult datasourceUserName = params.stream().filter(m -> m.getCode().equals(SystemConstant.DATA_DATASOURCE_USERNAME)).findFirst().orElse(null);
         if (datasourceUserName == null || StringUtils.isBlank(datasourceUserName.getValue().toString())) {
             throw ExceptionResultEnum.ERROR.exception("未设置用户名");
         }
         String userName = datasourceUserName.getValue().toString().trim();
         // 数据库密码
-        SysConfigResult datasourcePassword = params.stream().filter(m->m.getCode().equals(SystemConstant.DATA_DATASOURCE_PASSWORD)).findFirst().orElse(null);
+        SysConfigResult datasourcePassword = params.stream().filter(m -> m.getCode().equals(SystemConstant.DATA_DATASOURCE_PASSWORD)).findFirst().orElse(null);
         if (datasourcePassword == null || StringUtils.isBlank(datasourcePassword.getValue().toString())) {
             throw ExceptionResultEnum.ERROR.exception("未设置密码");
         }
@@ -245,7 +284,7 @@ public class DataUtil {
         String driverClassName;
         String url;
         if ("ORACLE".equals(type)) {
-            driverClassName = "com.mysql.jdbc.Driver";
+            driverClassName = "oracle.jdbc.driver.OracleDriver";
             url = "jdbc:oracle:thin:@" + host + ":" + port + ":" + dataName;
         } else if ("MYSQL".equals(type)) {
             driverClassName = "com.mysql.jdbc.Driver";
@@ -261,38 +300,4 @@ public class DataUtil {
         return new DriverManagerDataSource(url, userName, password);
     }
 
-    public static void main(String[] args) {
-        sqlConn("0", "localhost", "3306", "teachcloud-3.4.3", "root", "12345678");
-
-    }
-
-    public static String sqlConn(String databaseType, String address, String port, String databaseName, String userName, String password) {
-        String driverName = null;
-        String url = null;
-        if ("0".equals(databaseType)) {
-            //mysql
-            driverName = "com.mysql.cj.jdbc.Driver";
-            url = "jdbc:mysql://" + address + ":" + port + "/" + databaseName + "?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8";
-        } else if ("1".equals(databaseType)) {
-            //oracle
-            driverName = "oracle.jdbc.driver.OracleDriver";
-            url = "jdbc:oracle:thin:@" + address + ":" + port + ":" + databaseName;
-        } else if ("2".equals(databaseType)) {
-            //sqlserver
-            driverName = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
-            url = "jdbc:sqlserver://" + address + ":" + port + ";DatabaseName=" + databaseName;
-        }
-        try {
-            Class.forName(driverName);
-            Connection connection = DriverManager.getConnection(url, userName, password);
-            connection.close();
-        } catch (Exception e) {
-            return "测试失败";
-        }
-        return "测试成功";
-    }
-
-    public List<ExamStudentDataVo> listExamStudent(JdbcTemplate jdbcTemplate) {
-        return null;
-    }
 }

+ 15 - 3
teachcloud-data/src/main/java/com/qmth/teachcloud/data/entity/TSyncDataLog.java

@@ -8,6 +8,7 @@ import java.io.Serializable;
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
 import com.github.jeffreyning.mybatisplus.anno.MppMultiId;
+import com.qmth.teachcloud.common.annotation.EditKey;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
@@ -25,18 +26,21 @@ public class TSyncDataLog implements Serializable {
 
     private static final long serialVersionUID = 1L;
 
+    @JsonSerialize(using = ToStringSerializer.class)
+    @ApiModelProperty(value = "ID")
+    @TableId(value = "id")
+    @EditKey
+    private Long id;
+
     @JsonSerialize(using = ToStringSerializer.class)
     @ApiModelProperty(value = "学校ID")
-    @MppMultiId(value = "school_id")
     private Long schoolId;
 
     @JsonSerialize(using = ToStringSerializer.class)
     @ApiModelProperty(value = "考试ID")
-    @MppMultiId(value = "exam_id")
     private Long examId;
 
     @ApiModelProperty(value = "同步数据类型")
-    @MppMultiId(value = "data_type")
     private String dataType;
 
     @ApiModelProperty(value = "开始同步时间")
@@ -51,6 +55,14 @@ public class TSyncDataLog implements Serializable {
     @ApiModelProperty(value = "失败原因")
     private String errorMsg;
 
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
     public Long getSchoolId() {
         return schoolId;
     }

+ 25 - 0
teachcloud-data/src/main/java/com/qmth/teachcloud/data/enums/DataType.java

@@ -0,0 +1,25 @@
+package com.qmth.teachcloud.data.enums;
+
+public enum DataType {
+    A("v_org", "组织架构"),
+    B("v_user", "用户数据"),
+    C("v_course", "课程数据"),
+    D("v_student", "考生数据"),
+    E("v_exam_task", "命题任务数据");
+
+    DataType(String table, String name) {
+        this.table = table;
+        this.name = name;
+    }
+
+    private String table;
+    private String name;
+
+    public String getTable() {
+        return table;
+    }
+
+    public String getName() {
+        return name;
+    }
+}

+ 0 - 1
teachcloud-data/src/main/java/com/qmth/teachcloud/data/mapper/TSyncDataMapper.java

@@ -4,7 +4,6 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.github.jeffreyning.mybatisplus.base.MppBaseMapper;
 import com.qmth.teachcloud.data.entity.TSyncData;
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import org.apache.ibatis.annotations.Param;
 
 /**

+ 1 - 0
teachcloud-data/src/main/java/com/qmth/teachcloud/data/service/DataService.java

@@ -1,5 +1,6 @@
 package com.qmth.teachcloud.data.service;
 
+
 import com.qmth.distributed.print.business.bean.params.SysAdminSetParam;
 import com.qmth.teachcloud.data.entity.TSyncData;
 

+ 1 - 1
teachcloud-data/src/main/java/com/qmth/teachcloud/data/service/TSyncDataService.java

@@ -15,7 +15,7 @@ import com.qmth.teachcloud.data.entity.TSyncDataLog;
  */
 public interface TSyncDataService extends IMppService<TSyncData> {
 
-    boolean saveData(TSyncData tSyncData);
+    TSyncData saveData(TSyncData tSyncData);
 
     boolean syncData(Long schoolId, Long examId);
 

+ 162 - 65
teachcloud-data/src/main/java/com/qmth/teachcloud/data/service/impl/DataServiceImpl.java

@@ -1,23 +1,38 @@
 package com.qmth.teachcloud.data.service.impl;
 
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.qmth.distributed.print.business.bean.params.SysAdminSetParam;
+import com.qmth.distributed.print.business.service.BasicExamStudentService;
+import com.qmth.distributed.print.business.service.BasicMessageService;
 import com.qmth.distributed.print.business.service.ExamTaskService;
 import com.qmth.teachcloud.common.bean.sync.*;
+import com.qmth.teachcloud.common.contant.SystemConstant;
+import com.qmth.teachcloud.common.entity.BasicSchool;
+import com.qmth.teachcloud.common.entity.SysConfig;
 import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
+import com.qmth.teachcloud.common.enums.MessageEnum;
 import com.qmth.teachcloud.common.service.BasicCourseService;
+import com.qmth.teachcloud.common.service.CommonCacheService;
 import com.qmth.teachcloud.common.service.SysOrgService;
 import com.qmth.teachcloud.common.service.SysUserService;
 import com.qmth.teachcloud.data.DataUtil;
 import com.qmth.teachcloud.data.entity.TSyncData;
+import com.qmth.teachcloud.common.bean.sync.TSyncDataStudent;
+import com.qmth.teachcloud.data.enums.DataType;
 import com.qmth.teachcloud.data.service.DataService;
 import com.qmth.teachcloud.data.service.TSyncDataLogService;
+import com.qmth.teachcloud.data.service.TSyncDataStudentService;
 import com.qmth.teachcloud.data.util.JdbcUtil;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.StringJoiner;
 
 @Service
 public class DataServiceImpl implements DataService {
@@ -27,13 +42,21 @@ public class DataServiceImpl implements DataService {
     @Resource
     private TSyncDataLogService tSyncDataLogService;
     @Resource
+    private TSyncDataStudentService tSyncDataStudentService;
+    @Resource
     private BasicCourseService basicCourseService;
     @Resource
+    private BasicExamStudentService basicExamStudentService;
+    @Resource
+    private CommonCacheService commonCacheService;
+    @Resource
     private SysOrgService sysOrgService;
     @Resource
     private SysUserService sysUserService;
     @Resource
     private ExamTaskService examTaskService;
+    @Resource
+    private BasicMessageService basicMessageService;
 
     @Override
     public boolean testConnect(SysAdminSetParam sysAdminSetParam) {
@@ -55,81 +78,155 @@ public class DataServiceImpl implements DataService {
     public void syncData(Long schoolId, Long examId, TSyncData syncData) {
         JdbcTemplate jdbcTemplate = JdbcUtil.getJdbcTemplate(dataUtil.createDataSourceMap(schoolId));
         String dataRange = syncData.getDataType();
+
+        SysConfig datasourceType = commonCacheService.addSysConfigCache(schoolId, SystemConstant.DATA_DATASOURCE_TYPE);
+        if (datasourceType == null || StringUtils.isBlank(datasourceType.getConfigValue())) {
+            throw ExceptionResultEnum.ERROR.exception("未设置数据库类型");
+        }
+
+        boolean sendSms = false;
+        StringJoiner stringJoiner = new StringJoiner(";");
         // 机构同步
-        if (dataRange.contains("A")) {
-            long startTime = System.currentTimeMillis();
-            List<OrgDataVo> dataVoList = dataUtil.listOrg(jdbcTemplate);
-            int count = dataVoList.size();
-            String errorMsg = null;
-            try {
-                for (OrgDataVo orgDataVo : dataVoList) {
-                    sysOrgService.saveOrgFromSync(schoolId, orgDataVo);
-                }
-            } catch (Exception e) {
-                count = 0;
-                errorMsg = e.getMessage();
-            } finally {
-                long endTime = System.currentTimeMillis();
-                tSyncDataLogService.saveLog(schoolId, examId, "A", startTime, endTime, count, errorMsg);
-            }
+        if (dataRange.contains(DataType.A.name())) {
+            int count = syncOrg(jdbcTemplate, schoolId, examId, datasourceType.getConfigValue().toString());
+            stringJoiner.add(DataType.A.name() + ":" + count);
+            sendSms = count == 0 ? true : sendSms;
         }
         // 用户同步
-        if (dataRange.contains("B")) {
-            long startTime = System.currentTimeMillis();
-            List<UserDataVo> dataVoList = dataUtil.listUser(jdbcTemplate);
-            int count = dataVoList.size();
-            String errorMsg = null;
-            try {
-                for (UserDataVo userDataVo : dataVoList) {
-                    sysUserService.saveUserFromSync(schoolId, userDataVo);
-                }
-            } catch (Exception e) {
-                count = 0;
-                errorMsg = e.getMessage();
-            } finally {
-                long endTime = System.currentTimeMillis();
-                tSyncDataLogService.saveLog(schoolId, examId, "B", startTime, endTime, count, errorMsg);
-            }
+        if (dataRange.contains(DataType.B.name())) {
+            int count = syncUser(jdbcTemplate, schoolId, examId, datasourceType.getConfigValue().toString());
+            stringJoiner.add(DataType.B.name() + ":" + count);
+            sendSms = count == 0 ? true : sendSms;
         }
         // 课程同步
-        if (dataRange.contains("C")) {
-            long startTime = System.currentTimeMillis();
-            List<CourseDataVo> dataVoList = dataUtil.listCourse(jdbcTemplate);
-            int count = dataVoList.size();
-            String errorMsg = null;
-            try {
-                for (CourseDataVo courseDataVo : dataVoList) {
-                    basicCourseService.saveBasicCourseFormSync(schoolId, courseDataVo);
-                }
-            } catch (Exception e) {
-                count = 0;
-                errorMsg = e.getMessage();
-            } finally {
-                long endTime = System.currentTimeMillis();
-                tSyncDataLogService.saveLog(schoolId, examId, "C", startTime, endTime, count, errorMsg);
-            }
+        if (dataRange.contains(DataType.C.name())) {
+            int count = syncCourse(jdbcTemplate, schoolId, examId, datasourceType.getConfigValue().toString());
+            stringJoiner.add(DataType.C.name() + ":" + count);
+            sendSms = count == 0 ? true : sendSms;
         }
         // 考生同步
-        if (dataRange.contains("D")) {
-            List<ExamStudentDataVo> dataVoList = dataUtil.listExamStudent(jdbcTemplate);
+        if (dataRange.contains(DataType.D.name())) {
+            int count = syncStudent(jdbcTemplate, schoolId, examId, datasourceType.getConfigValue().toString());
+            stringJoiner.add(DataType.D.name() + ":" + count);
+            sendSms = count == 0 ? true : sendSms;
         }
         // 命题任务同步
-        if (dataRange.contains("E")) {
-            long startTime = System.currentTimeMillis();
-            List<ExamTaskDataVo> dataVoList = dataUtil.listExamTask(jdbcTemplate);
-            int count = dataVoList.size();
-            String errorMsg = null;
-            try {
-                for (ExamTaskDataVo examTaskDataVo : dataVoList) {
-                    examTaskService.saveExamTaskFormSync(schoolId, examId, examTaskDataVo);
-                }
-            } catch (Exception e) {
-                count = 0;
-                errorMsg = e.getMessage();
-            } finally {
-                long endTime = System.currentTimeMillis();
-                tSyncDataLogService.saveLog(schoolId, examId, "C", startTime, endTime, count, errorMsg);
+        if (dataRange.contains(DataType.E.name())) {
+            int count = syncExamTask(jdbcTemplate, schoolId, examId, datasourceType.getConfigValue().toString());
+            stringJoiner.add(DataType.E.name() + ":" + count);
+            sendSms = count == 0 ? true : sendSms;
+        }
+
+        syncData.setDetail(stringJoiner.toString());
+
+        // 有一个失败,发送短信
+        if (sendSms && StringUtils.isNotBlank(syncData.getPhoneNumber())) {
+            BasicSchool basicSchool = commonCacheService.schoolCache(schoolId);
+            Map<String, String> variableParams = new HashMap<>();
+            variableParams.put("schoolName", basicSchool.getName());
+            for (String phoneNumber : syncData.getPhoneNumber().split(",")) {
+                basicMessageService.saveMessageSendLog(schoolId, null, null, phoneNumber, JSON.toJSONString(variableParams), MessageEnum.NOTICE_SYNC_DATA);
             }
         }
     }
+
+    private int syncOrg(JdbcTemplate jdbcTemplate, Long schoolId, Long examId, String datasourceType) {
+        long startTime = System.currentTimeMillis();
+        List<OrgDataVo> dataVoList = dataUtil.listOrg(jdbcTemplate, DataType.A, datasourceType);
+        int count = dataVoList.size();
+        String errorMsg = null;
+        try {
+            for (OrgDataVo orgDataVo : dataVoList) {
+                sysOrgService.saveOrgFromSync(schoolId, orgDataVo);
+            }
+        } catch (Exception e) {
+            count = 0;
+            errorMsg = e.getMessage();
+        } finally {
+            long endTime = System.currentTimeMillis();
+            tSyncDataLogService.saveLog(schoolId, examId, DataType.A.name(), startTime, endTime, count, errorMsg);
+        }
+        return count;
+    }
+
+    private int syncUser(JdbcTemplate jdbcTemplate, Long schoolId, Long examId, String datasourceType) {
+        long startTime = System.currentTimeMillis();
+        List<UserDataVo> dataVoList = dataUtil.listUser(jdbcTemplate, DataType.B, datasourceType);
+        int count = dataVoList.size();
+        String errorMsg = null;
+        try {
+            for (UserDataVo userDataVo : dataVoList) {
+                sysUserService.saveUserFromSync(schoolId, userDataVo);
+            }
+        } catch (Exception e) {
+            count = 0;
+            errorMsg = e.getMessage();
+        } finally {
+            long endTime = System.currentTimeMillis();
+            tSyncDataLogService.saveLog(schoolId, examId, DataType.B.name(), startTime, endTime, count, errorMsg);
+        }
+        return count;
+    }
+
+    private int syncCourse(JdbcTemplate jdbcTemplate, Long schoolId, Long examId, String datasourceType) {
+        long startTime = System.currentTimeMillis();
+        List<CourseDataVo> dataVoList = dataUtil.listCourse(jdbcTemplate, DataType.C, datasourceType);
+        int count = dataVoList.size();
+        String errorMsg = null;
+        try {
+            for (CourseDataVo courseDataVo : dataVoList) {
+                basicCourseService.saveBasicCourseFormSync(schoolId, courseDataVo);
+            }
+        } catch (Exception e) {
+            count = 0;
+            errorMsg = e.getMessage();
+        } finally {
+            long endTime = System.currentTimeMillis();
+            tSyncDataLogService.saveLog(schoolId, examId, DataType.C.name(), startTime, endTime, count, errorMsg);
+        }
+        return count;
+    }
+
+    private int syncStudent(JdbcTemplate jdbcTemplate, Long schoolId, Long examId, String datasourceType) {
+        long startTime = System.currentTimeMillis();
+        List<TSyncDataStudent> dataVoList = dataUtil.listExamStudent(jdbcTemplate, DataType.D, datasourceType);
+        int count = dataVoList.size();
+        String errorMsg = null;
+        try {
+            for (TSyncDataStudent tSyncDataStudent : dataVoList) {
+                tSyncDataStudent.setId(SystemConstant.getDbUuid());
+                tSyncDataStudent.setSchoolId(schoolId);
+                tSyncDataStudent.setExamId(examId);
+            }
+            tSyncDataStudentService.remove(new UpdateWrapper<TSyncDataStudent>().lambda().eq(TSyncDataStudent::getSchoolId, schoolId).eq(TSyncDataStudent::getExamId, examId));
+            tSyncDataStudentService.saveBatch(dataVoList, 2000);
+            basicExamStudentService.saveBasicExamStudentFormSync(schoolId, examId, dataVoList);
+        } catch (Exception e) {
+            count = 0;
+            errorMsg = e.getMessage();
+        } finally {
+            long endTime = System.currentTimeMillis();
+            tSyncDataLogService.saveLog(schoolId, examId, DataType.D.name(), startTime, endTime, count, errorMsg);
+        }
+        return count;
+    }
+
+    private int syncExamTask(JdbcTemplate jdbcTemplate, Long schoolId, Long examId, String datasourceType) {
+        long startTime = System.currentTimeMillis();
+        List<ExamTaskDataVo> dataVoList = dataUtil.listExamTask(jdbcTemplate, DataType.E, datasourceType);
+        int count = dataVoList.size();
+        String errorMsg = null;
+        try {
+            for (ExamTaskDataVo examTaskDataVo : dataVoList) {
+                examTaskService.saveExamTaskFormSync(schoolId, examId, examTaskDataVo);
+            }
+        } catch (Exception e) {
+            count = 0;
+            errorMsg = e.getMessage();
+        } finally {
+            long endTime = System.currentTimeMillis();
+            tSyncDataLogService.saveLog(schoolId, examId, DataType.E.name(), startTime, endTime, count, errorMsg);
+        }
+        return count;
+    }
 }

+ 1 - 0
teachcloud-data/src/main/java/com/qmth/teachcloud/data/service/impl/TSyncDataLogServiceImpl.java

@@ -20,6 +20,7 @@ public class TSyncDataLogServiceImpl extends MppServiceImpl<TSyncDataLogMapper,
     @Override
     public void saveLog(Long schoolId, Long examId, String dataType, long startTime, long endTime, int count, String errorMsg) {
         TSyncDataLog tSyncDataLog = new TSyncDataLog();
+        tSyncDataLog.setId(System.currentTimeMillis());
         tSyncDataLog.setSchoolId(schoolId);
         tSyncDataLog.setExamId(examId);
         tSyncDataLog.setDataType(dataType);

+ 9 - 6
teachcloud-data/src/main/java/com/qmth/teachcloud/data/service/impl/TSyncDataServiceImpl.java

@@ -7,7 +7,6 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.github.jeffreyning.mybatisplus.service.MppServiceImpl;
 import com.qmth.boot.core.concurrent.service.ConcurrentService;
 import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
-import com.qmth.teachcloud.data.DataUtil;
 import com.qmth.teachcloud.data.entity.TSyncData;
 import com.qmth.teachcloud.data.entity.TSyncDataLog;
 import com.qmth.teachcloud.data.mapper.TSyncDataMapper;
@@ -33,16 +32,17 @@ public class TSyncDataServiceImpl extends MppServiceImpl<TSyncDataMapper, TSyncD
     private DataService dataService;
     @Resource
     private TSyncDataLogService tSyncDataLogService;
-    private DataUtil dataUtil;
     @Resource
     private ConcurrentService concurrentService;
 
     @Override
-    public boolean saveData(TSyncData tSyncData) {
+    public TSyncData saveData(TSyncData tSyncData) {
         TSyncData syncData = this.selectByMultiId(new TSyncData(tSyncData.getSchoolId(), tSyncData.getExamId()));
         if (syncData == null) {
             tSyncData.setCreateTime(System.currentTimeMillis());
             this.saveOrUpdateByMultiId(tSyncData);
+
+            return tSyncData;
         } else {
             if (syncData.getStatus()) {
                 throw ExceptionResultEnum.ERROR.exception("数据同步中,不能修改");
@@ -54,8 +54,9 @@ public class TSyncDataServiceImpl extends MppServiceImpl<TSyncDataMapper, TSyncD
             syncData.setPhoneNumber(tSyncData.getPhoneNumber());
             syncData.setUpdateTime(System.currentTimeMillis());
             this.updateByMultiId(syncData);
+
+            return syncData;
         }
-        return true;
     }
 
     @Override
@@ -89,7 +90,7 @@ public class TSyncDataServiceImpl extends MppServiceImpl<TSyncDataMapper, TSyncD
         QueryWrapper<TSyncDataLog> queryWrapper = new QueryWrapper<>();
         queryWrapper.lambda().eq(TSyncDataLog::getSchoolId, schoolId)
                 .eq(TSyncDataLog::getExamId, examId)
-                .orderByAsc(TSyncDataLog::getDataType);
+                .orderByDesc(TSyncDataLog::getStartTime);
         return tSyncDataLogService.page(page, queryWrapper);
     }
 
@@ -105,7 +106,9 @@ public class TSyncDataServiceImpl extends MppServiceImpl<TSyncDataMapper, TSyncD
         updateWrapper.lambda().set(TSyncData::getEnable, tSyncData.getEnable())
                 .eq(TSyncData::getSchoolId, tSyncData.getSchoolId())
                 .eq(TSyncData::getExamId, tSyncData.getExamId());
-        return this.update(updateWrapper);
+        this.update(updateWrapper);
+        return true;
     }
 
+
 }

+ 1 - 0
teachcloud-data/src/main/resources/mapper/TSyncDataMapper.xml

@@ -25,6 +25,7 @@
                 LEFT JOIN
             basic_semester bs ON be.semester_id = bs.id
         where tsd.school_id = #{schoolId}
+        order by tsd.create_time desc
     </select>
 
 </mapper>

+ 11 - 1
teachcloud-task/src/main/java/com/qmth/teachcloud/task/job/DataSyncJob.java

@@ -2,8 +2,11 @@ package com.qmth.teachcloud.task.job;
 
 import com.qmth.teachcloud.common.contant.SystemConstant;
 import com.qmth.teachcloud.task.job.service.JobService;
+import org.apache.commons.lang3.StringUtils;
+import org.quartz.JobDetail;
 import org.quartz.JobExecutionContext;
 import org.quartz.JobExecutionException;
+import org.quartz.Trigger;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.scheduling.quartz.QuartzJobBean;
@@ -22,7 +25,14 @@ public class DataSyncJob extends QuartzJobBean {
     @Override
     protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
         try {
-            jobService.sentDataSync();
+            String name = jobExecutionContext.getJobDetail().getKey().getName();
+            if (StringUtils.isNotBlank(name)) {
+                String[] names = name.split("-");
+                if (names.length > 2) {
+                    // 传入学校ID、考试ID
+                    jobService.sentDataSync(names[names.length - 2], names[names.length - 1]);
+                }
+            }
         } catch (Exception e) {
             log.error(SystemConstant.LOG_ERROR, e);
         }

+ 1 - 1
teachcloud-task/src/main/java/com/qmth/teachcloud/task/job/service/JobService.java

@@ -52,5 +52,5 @@ public interface JobService {
 
     void createPdfTask();
 
-    void sentDataSync();
+    void sentDataSync(String name, String s);
 }

+ 7 - 10
teachcloud-task/src/main/java/com/qmth/teachcloud/task/job/service/impl/JobServiceImpl.java

@@ -7,11 +7,11 @@ import com.qmth.distributed.print.business.entity.*;
 import com.qmth.distributed.print.business.enums.ExamDetailStatusEnum;
 import com.qmth.distributed.print.business.service.*;
 import com.qmth.distributed.print.business.templete.execute.AsyncCreatePdfTemplateService;
+import com.qmth.distributed.print.business.util.ExamTaskUtil;
 import com.qmth.teachcloud.common.bean.dto.MqDto;
 import com.qmth.teachcloud.common.bean.vo.PaperInfoVo;
 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.TSAuth;
 import com.qmth.teachcloud.common.enums.AuthEnum;
 import com.qmth.teachcloud.common.enums.PushTypeEnum;
@@ -22,9 +22,7 @@ import com.qmth.teachcloud.common.service.BasicCourseService;
 import com.qmth.teachcloud.common.service.TSAuthService;
 import com.qmth.teachcloud.common.threadPool.DynamicMyThreadPool;
 import com.qmth.teachcloud.common.util.DateDisposeUtils;
-import com.qmth.distributed.print.business.util.ExamTaskUtil;
 import com.qmth.teachcloud.common.util.RedisUtil;
-import com.qmth.teachcloud.data.entity.TSyncData;
 import com.qmth.teachcloud.data.service.TSyncDataService;
 import com.qmth.teachcloud.mark.entity.MarkGroup;
 import com.qmth.teachcloud.mark.entity.MarkPaper;
@@ -36,20 +34,18 @@ import com.qmth.teachcloud.mark.service.MarkPaperService;
 import com.qmth.teachcloud.mark.service.MarkService;
 import com.qmth.teachcloud.mark.service.MarkUserGroupService;
 import com.qmth.teachcloud.mark.utils.TaskLockUtil;
-import com.qmth.teachcloud.task.enums.JobEnum;
-import com.qmth.teachcloud.task.job.DataSyncJob;
-import com.qmth.teachcloud.task.job.SendSmsExpireJob;
 import com.qmth.teachcloud.task.job.service.JobService;
 import com.qmth.teachcloud.task.service.PrintFinishService;
-import com.qmth.teachcloud.task.service.QuartzService;
 import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
-import java.util.*;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
@@ -263,7 +259,8 @@ public class JobServiceImpl implements JobService {
     }
 
     @Override
-    public void sentDataSync() {
+    public void sentDataSync(String schoolId, String examId) {
+        tSyncDataService.syncData(Long.valueOf(schoolId), Long.valueOf(examId));
     }
 
     /**