Sfoglia il codice sorgente

教培计划代码提交

jingyuanchao 2 anni fa
parent
commit
80ed229521

+ 2 - 2
soc-api/soc-api-system/src/main/java/com/xunmei/system/api/domain/SysOrg.java

@@ -98,9 +98,9 @@ public class SysOrg extends BaseEntity {
     @TableField(value = "sort")
     @ApiModelProperty(value = "排序")
     private Double sort;
-    @ApiModelProperty(value = "天气城市区域编码")
+/*    @ApiModelProperty(value = "天气城市区域编码")
     @TableField(value = "weather_city_code")
-    private String weatherCityCode;
+    private String weatherCityCode;*/
 
     @JsonSerialize(using = ToStringSerializer.class)
     @TableField(value = "org_extend_id")

+ 3 - 2
soc-common/soc-common-core/src/main/java/com/xunmei/common/core/domain/edu/vo/CoreEduTrainingPlanPageVo.java

@@ -62,9 +62,10 @@ public class CoreEduTrainingPlanPageVo {
     @ApiModelProperty(value = "是否由顶级机构创建", notes = "0:否 1:是")
     private int createByTopOrg;
 
+    @ApiModelProperty(value = "标准机构下发的计划所生成任务是否存在已完成的任务", notes = "1:存在, 0/null:不存在")
+    private Integer done;
+
     private String planRoleNameList;
-    @JsonIgnore
-    private Boolean hasChildren;
 
     private List<CoreEduTrainingPlanPageVo> children;
 }

+ 25 - 0
soc-common/soc-common-redis/src/main/java/com/xunmei/common/redis/aop/RepeatSubmitCheck.java

@@ -0,0 +1,25 @@
+package com.xunmei.common.redis.aop;
+
+import java.lang.annotation.*;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author jingyuanchao
+ * @date 2023/3/8 10:17
+ */
+
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface RepeatSubmitCheck {
+
+    /**
+     * 幂等时间间隔(秒)
+     * @return
+     */
+    int expired() default 3;
+
+    TimeUnit timeUnit() default TimeUnit.SECONDS;
+
+    String message() default "请勿重复提交";
+}

+ 128 - 0
soc-common/soc-common-redis/src/main/java/com/xunmei/common/redis/aop/RepeatSubmitCheckAspect.java

@@ -0,0 +1,128 @@
+package com.xunmei.common.redis.aop;
+
+import cn.hutool.core.convert.Convert;
+import com.alibaba.fastjson2.JSON;
+import com.xunmei.common.core.web.domain.AjaxResult;
+import com.xunmei.common.redis.utils.RedisUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.redisson.api.RBucket;
+import org.redisson.api.RedissonClient;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.xml.bind.DatatypeConverter;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * @author jingyuanchao
+ * @date 2023/3/8 10:18
+ */
+@Aspect
+@Component
+public class RepeatSubmitCheckAspect {
+    @Resource
+    private HttpServletRequest request;
+
+    private static final RedissonClient redissonClient = RedisUtils.getClient();
+
+    public static final String CONSTANT_REPEAT_KEY = "constant_repeat_key_";
+
+    @Before("@annotation(com.xunmei.common.redis.aop.RepeatSubmitCheck)")
+    public void handle(JoinPoint joinPoint) throws Exception {
+
+        //获取注解的信息
+        RepeatSubmitCheck annotation = this.getDeclaredAnnotation(joinPoint);
+        final boolean repeatSubmit = this.isRepeatSubmit(joinPoint, annotation);
+        if (repeatSubmit) {
+            HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
+            response.setStatus(HttpStatus.OK.value());
+            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
+            response.setCharacterEncoding(StandardCharsets.UTF_8.name());
+            ;
+            response.getWriter().print(JSON.toJSONString(AjaxResult.error(annotation.message())));
+            throw new RuntimeException("重复提交");
+        }
+    }
+
+    /**
+     * 获取方法中声明的注解
+     *
+     * @param joinPoint
+     * @return
+     * @throws NoSuchMethodException
+     */
+    public RepeatSubmitCheck getDeclaredAnnotation(JoinPoint joinPoint) throws NoSuchMethodException {
+        // 获取方法名
+        String methodName = joinPoint.getSignature().getName();
+        // 反射获取目标类
+        Class<?> targetClass = joinPoint.getTarget().getClass();
+        // 拿到方法对应的参数类型
+        Class<?>[] parameterTypes = ((MethodSignature) joinPoint.getSignature()).getParameterTypes();
+        // 根据类、方法、参数类型(重载)获取到方法的具体信息
+        Method objMethod = targetClass.getMethod(methodName, parameterTypes);
+        // 拿到方法定义的注解信息
+        RepeatSubmitCheck annotation = objMethod.getDeclaredAnnotation(RepeatSubmitCheck.class);
+        // 返回
+        return annotation;
+    }
+
+    /**
+     * 判断是否重复提交
+     *
+     * @param joinPoint  切点
+     * @param annotation 幂等注解
+     * @return 重复提交请求返回true
+     */
+    private boolean isRepeatSubmit(JoinPoint joinPoint, RepeatSubmitCheck annotation) throws IOException, NoSuchAlgorithmException {
+        // 常量+URI为Redis的Key,请求参数md5摘要为Value
+
+        String key = CONSTANT_REPEAT_KEY + request.getRequestURI();
+        RBucket<String> bucket = redissonClient.getBucket(key);
+
+        // 获取参数值
+        Object[] args = joinPoint.getArgs();
+        StringBuilder sb = new StringBuilder();
+        for (Object arg : args) {
+            sb.append(Convert.toStr(arg));
+        }
+
+        // redis查询不为null,并且本次的请求参数md5与val相同则为重复请求
+        final String md5Value = jdkMD5(sb.toString());
+        if (StringUtils.isNotBlank(bucket.get())) {
+            return bucket.get().equals(md5Value);
+        }
+        // 如果redis中没有数据,将本次请求参数存入Redis,考虑到并发情况,trySet 如果已经存在则返回false,代表重复请求
+        return !bucket.trySet(md5Value, annotation.expired(), annotation.timeUnit());
+    }
+
+    /**
+     * 读取请求体内容
+     */
+    private String getRequestBody(HttpServletRequest request) throws IOException {
+        return IOUtils.toString(request.getReader());
+    }
+
+    /**
+     * MD5摘要并转换为字符串
+     */
+    private static String jdkMD5(String str) throws NoSuchAlgorithmException {
+        MessageDigest messageDigest = MessageDigest.getInstance("MD5");
+        byte[] mdBytes = messageDigest.digest(str.getBytes());
+        return DatatypeConverter.printHexBinary(mdBytes);
+    }
+}

+ 1 - 0
soc-modules/soc-modules-core/src/main/java/com/xunmei/core/drill/service/impl/CoreDrillPlanServiceImpl.java

@@ -84,6 +84,7 @@ public class CoreDrillPlanServiceImpl extends ServiceImpl<CoreDrillPlanMapper, C
         return TableDataInfo.build();
     }
 
+
     private void dealData(CoreDrillPlanPageVo record, List<CoreDrillPlanPageVo> records, Long orgId, CoreDrillPlanPageDto request) {
         record.setNo(records.indexOf(record) + 1);
         if (ObjectUtil.equal(record.getCreateOrgId(), orgId)) {

+ 1 - 1
soc-modules/soc-modules-core/src/main/java/com/xunmei/core/edu/controller/CoreEduTrainingPlanController.java

@@ -82,7 +82,7 @@ public class CoreEduTrainingPlanController extends BaseController {
     @RequiresPermissions("core:plan:remove")
     @Log(title = "教育培训计划", businessType = BusinessType.DELETE)
     @DeleteMapping("/{ids}")
-    public AjaxResult remove(@PathVariable Long[] ids) {
+    public AjaxResult remove(@PathVariable Long ids) {
         return toAjax(coreEduTrainingPlanService.deleteCoreEduTrainingPlanByIds(ids));
     }
 

+ 2 - 0
soc-modules/soc-modules-core/src/main/java/com/xunmei/core/edu/controller/SysKnowledgeController.java

@@ -3,6 +3,7 @@ package com.xunmei.core.edu.controller;
 import java.util.List;
 import com.xunmei.common.core.domain.IdName;
 import com.xunmei.common.core.domain.edu.domain.SysKnowledge;
+import com.xunmei.common.redis.aop.RepeatSubmitCheck;
 import com.xunmei.core.edu.service.ISysKnowledgeService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -59,6 +60,7 @@ public class SysKnowledgeController extends BaseController {
     /**
      * 新增知识库标签
      */
+    @RepeatSubmitCheck
     @ApiOperation(value = "新增SysKnowledge")
     @RequiresPermissions("core:knowledge:add")
     @Log(title = "知识库标签", businessType = BusinessType.INSERT)

+ 2 - 0
soc-modules/soc-modules-core/src/main/java/com/xunmei/core/edu/mapper/SysKnowledgeMapper.java

@@ -2,6 +2,7 @@ package com.xunmei.core.edu.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.xunmei.common.core.domain.edu.domain.SysKnowledge;
+import org.apache.ibatis.annotations.Param;
 
 import java.util.List;
 
@@ -63,4 +64,5 @@ public interface SysKnowledgeMapper extends BaseMapper<SysKnowledge> {
 
     List<SysKnowledge> dataList();
 
+    Integer checkInUse(@Param("list") List<Long> list);
 }

+ 1 - 1
soc-modules/soc-modules-core/src/main/java/com/xunmei/core/edu/service/ICoreEduTrainingPlanService.java

@@ -61,7 +61,7 @@ public interface ICoreEduTrainingPlanService extends IService<CoreEduTrainingPla
      * @param ids 需要删除的教育培训计划主键集合
      * @return 结果
      */
-    int deleteCoreEduTrainingPlanByIds(Long[] ids);
+    int deleteCoreEduTrainingPlanByIds(Long ids);
 
     /**
      * 删除教育培训计划信息

+ 51 - 10
soc-modules/soc-modules-core/src/main/java/com/xunmei/core/edu/service/impl/CoreEduTrainingPlanServiceImpl.java

@@ -112,13 +112,13 @@ public class CoreEduTrainingPlanServiceImpl extends ServiceImpl<CoreEduTrainingP
         request.setId(record.getId());
         List<CoreEduTrainingPlanPageVo> children = coreEduTrainingPlanMapper.selectChildrenPlan(request);
         record.setChildren(children);
-        record.setHasChildren(ObjectUtil.isNotEmpty(children));
         for (CoreEduTrainingPlanPageVo child : children) {
             if (ObjectUtil.equal(child.getCreateOrgId(), orgId)) {
                 child.setCreateByTopOrg(1);
             }
             child.setPlanRoleNameList(roleNameList);
         }
+
     }
 
 
@@ -265,13 +265,18 @@ public class CoreEduTrainingPlanServiceImpl extends ServiceImpl<CoreEduTrainingP
         Long planId = plan.getId();
         //删除原有数据, 然后重新生成计划,任务
         List<Long> planIdList = coreEduTrainingPlanMapper.selectIdByParentId(planId);
-        coreEduTrainingPlanMapper.deleteBatchIds(planIdList);
-        coreEduTrainingPlanToExecOrgMapper.delete(new LambdaQueryWrapper<CoreEduTrainingPlanToExecOrg>().in(CoreEduTrainingPlanToExecOrg::getPlanId, planIdList));
-        coreEduTrainingPlanToRoleMapper.delete(new LambdaQueryWrapper<CoreEduTrainingPlanToRole>().in(CoreEduTrainingPlanToRole::getPlanId, planIdList));
+        if (ObjectUtil.isNotEmpty(planIdList)) {
+            coreEduTrainingPlanMapper.deleteBatchIds(planIdList);
+            coreEduTrainingPlanToExecOrgMapper.delete(new LambdaQueryWrapper<CoreEduTrainingPlanToExecOrg>().in(CoreEduTrainingPlanToExecOrg::getPlanId, planIdList));
+            coreEduTrainingPlanToRoleMapper.delete(new LambdaQueryWrapper<CoreEduTrainingPlanToRole>().in(CoreEduTrainingPlanToRole::getPlanId, planIdList));
+        }
         List<CoreEduTrainingTask> taskIdList = coreEduTrainingTaskMapper.selectList(new LambdaQueryWrapper<CoreEduTrainingTask>().in(CoreEduTrainingTask::getPlanId, planIdList).select(CoreEduTrainingTask::getId));
         List<Long> collect = taskIdList.stream().map(CoreEduTrainingTask::getId).collect(Collectors.toList());
-        coreEduTrainingTaskMapper.deleteBatchIds(collect);
-        coreEduTrainingTaskToRoleMapper.delete(new LambdaQueryWrapper<CoreEduTrainingTaskToRole>().in(CoreEduTrainingTaskToRole::getEduTrainingTaskId, collect));
+        if (ObjectUtil.isNotEmpty(collect)) {
+            coreEduTrainingTaskMapper.deleteBatchIds(collect);
+            coreEduTrainingTaskToRoleMapper.delete(new LambdaQueryWrapper<CoreEduTrainingTaskToRole>().in(CoreEduTrainingTaskToRole::getEduTrainingTaskId, collect));
+
+        }
         List<CoreEduTrainingPlan> planList = buildPlanData(plan, trainingPlanToRoleList);
 
         for (CoreEduTrainingPlan trainingPlan : planList) {
@@ -406,17 +411,53 @@ public class CoreEduTrainingPlanServiceImpl extends ServiceImpl<CoreEduTrainingP
     /**
      * 批量删除教育培训计划
      *
-     * @param ids 需要删除的教育培训计划主键
+     * @param id 需要删除的教育培训计划主键
      * @return 结果
      */
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public int deleteCoreEduTrainingPlanByIds(Long[] ids) {
-        Integer count = coreEduTrainingTaskMapper.checkHasTaskIsDone(Arrays.asList(ids));
+    public int deleteCoreEduTrainingPlanByIds(Long id) {
+        Integer count = coreEduTrainingTaskMapper.checkHasTaskIsDone(Collections.singletonList(id));
         if (count != null && count > 0) {
             throw new RuntimeException("已有任务完成,无法删除");
         }
-        return coreEduTrainingPlanMapper.deleteBatchIds(Arrays.asList((ids)));
+        final Integer done = coreEduTrainingTaskMapper.checkHasTaskIsDoneByPlanParentId(id);
+        if (done != null && done > 0) {
+            throw new RuntimeException("已有任务完成,无法删除");
+        }
+        final CoreEduTrainingPlan plan = getById(id);
+        if (plan.getStandard() == 0) {
+            //自建计划
+            final List<CoreEduTrainingTask> coreEduTrainingTasks = coreEduTrainingTaskMapper.selectList(new LambdaQueryWrapper<CoreEduTrainingTask>()
+                    .eq(CoreEduTrainingTask::getPlanId, id)
+                    .select(CoreEduTrainingTask::getId));
+            final List<Long> taskIdList = coreEduTrainingTasks.stream().map(CoreEduTrainingTask::getId).collect(Collectors.toList());
+            //删除任务相关
+            if (ObjectUtil.isNotEmpty(taskIdList)){
+                coreEduTrainingTaskMapper.deleteBatchIds(taskIdList);
+                coreEduTrainingTaskToRoleMapper.deleteByMap(MapUtil.of("edu_training_task_id", taskIdList));
+                return coreEduTrainingPlanMapper.deleteBatchIds(Collections.singletonList((id)));
+            }
+            //删除计划
+            return coreEduTrainingPlanMapper.deleteBatchIds(Collections.singletonList((id)));
+        } else {
+            //标准计划
+            List<Long> planIdList = coreEduTrainingPlanMapper.selectIdByParentId(id);
+            if (ObjectUtil.isNotEmpty(planIdList)) {
+                //删除任务相关
+                final List<CoreEduTrainingTask> trainingTaskList = coreEduTrainingTaskMapper.selectList(new LambdaQueryWrapper<CoreEduTrainingTask>()
+                        .in(CoreEduTrainingTask::getPlanId, planIdList)
+                        .select(CoreEduTrainingTask::getId));
+                final List<Long> taskIdList = trainingTaskList.stream().map(CoreEduTrainingTask::getId).collect(Collectors.toList());
+                if (ObjectUtil.isNotEmpty(taskIdList)){
+                    coreEduTrainingTaskMapper.deleteBatchIds(taskIdList);
+                    coreEduTrainingTaskToRoleMapper.deleteByMap(MapUtil.of("edu_training_task_id", taskIdList));
+                }
+            }
+            //删除计划
+            planIdList.add(id);
+            return coreEduTrainingPlanMapper.deleteBatchIds(planIdList);
+        }
     }
 
     /**

+ 11 - 1
soc-modules/soc-modules-core/src/main/java/com/xunmei/core/edu/service/impl/SysKnowledgeServiceImpl.java

@@ -11,10 +11,12 @@ import com.xunmei.common.core.utils.StringUtils;
 import com.xunmei.common.core.web.page.TableDataInfo;
 import com.xunmei.common.security.utils.SecurityUtils;
 import com.xunmei.core.edu.mapper.SysKnowledgeMapper;
+import com.xunmei.core.edu.mapper.SysLearningMaterialsMapper;
 import com.xunmei.core.edu.service.ISysKnowledgeService;
 import com.xunmei.system.api.RemoteOrgService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
 import java.util.Arrays;
 import java.util.Collections;
@@ -32,6 +34,8 @@ public class SysKnowledgeServiceImpl extends ServiceImpl<SysKnowledgeMapper, Sys
     @Autowired
     private SysKnowledgeMapper sysKnowledgeMapper;
     @Autowired
+    private SysLearningMaterialsMapper sysLearningMaterialsMapper;
+    @Autowired
     private RemoteOrgService orgService;
 
     @Override
@@ -125,8 +129,14 @@ public class SysKnowledgeServiceImpl extends ServiceImpl<SysKnowledgeMapper, Sys
      * @return 结果
      */
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public int deleteSysKnowledgeByIds(Long[] ids) {
-        return sysKnowledgeMapper.deleteBatchIds(Arrays.asList((ids)));
+        final List<Long> idList = Arrays.asList((ids));
+        Integer count = sysKnowledgeMapper.checkInUse(idList);
+        if (null != count && count > 0) {
+            throw new RuntimeException("知识库标签已被使用,无法删除");
+        }
+        return sysKnowledgeMapper.deleteBatchIds(idList);
     }
 
     /**

+ 1 - 1
soc-modules/soc-modules-core/src/main/resources/mapper/edu/CoreEduTrainingTaskMapper.xml

@@ -156,6 +156,6 @@
         from core_edu_training_task
         where status != 0
           and plan_id in
-              (select id from core_edu_training_plan where plan_status = 0 and deleted = 0 and parent_id = #{planId})
+              (select id from core_edu_training_plan where plan_status = 0 and deleted = 0 and parent_id = #{planId}) limit 1
     </select>
 </mapper>

+ 9 - 0
soc-modules/soc-modules-core/src/main/resources/mapper/edu/SysKnowledgeMapper.xml

@@ -113,4 +113,13 @@
             #{id}
         </foreach>
     </delete>
+
+    <select id="checkInUse" resultType="java.lang.Integer">
+        select 1 from sys_learning_materials m where m.deleted=0 and m.knowledge_id
+        in
+        <foreach collection="list" item="item" index="index" open="(" separator="," close=")">
+            #{item}
+        </foreach>
+        limit 1
+    </select>
 </mapper>