瀏覽代碼

加入视频存储管理

wangliang 2 年之前
父節點
當前提交
69b52976cc
共有 23 個文件被更改,包括 491 次插入40 次删除
  1. 78 6
      themis-admin/src/main/java/com/qmth/themis/admin/api/SysController.java
  2. 5 9
      themis-admin/src/main/java/com/qmth/themis/admin/api/TEExamController.java
  3. 2 3
      themis-admin/src/main/java/com/qmth/themis/admin/api/TEExamPaperController.java
  4. 2 3
      themis-admin/src/main/java/com/qmth/themis/admin/api/TEExamStudentController.java
  5. 129 0
      themis-business/src/main/java/com/qmth/themis/business/bean/result/VideoQueryResult.java
  6. 6 2
      themis-business/src/main/java/com/qmth/themis/business/constant/SystemConstant.java
  7. 12 0
      themis-business/src/main/java/com/qmth/themis/business/dao/TEExamMapper.java
  8. 10 0
      themis-business/src/main/java/com/qmth/themis/business/dao/TMTencentVideoMessageMapper.java
  9. 22 0
      themis-business/src/main/java/com/qmth/themis/business/entity/TEExam.java
  10. 44 0
      themis-business/src/main/java/com/qmth/themis/business/enums/VideoTypeEnum.java
  11. 1 1
      themis-business/src/main/java/com/qmth/themis/business/service/CommonService.java
  12. 13 0
      themis-business/src/main/java/com/qmth/themis/business/service/TEExamService.java
  13. 10 0
      themis-business/src/main/java/com/qmth/themis/business/service/TMTencentVideoMessageService.java
  14. 2 2
      themis-business/src/main/java/com/qmth/themis/business/service/impl/CommonServiceImpl.java
  15. 16 1
      themis-business/src/main/java/com/qmth/themis/business/service/impl/TEExamServiceImpl.java
  16. 17 0
      themis-business/src/main/java/com/qmth/themis/business/service/impl/TMTencentVideoMessageServiceImpl.java
  17. 2 3
      themis-business/src/main/java/com/qmth/themis/business/templete/impl/TaskExamPaperImportTemplete.java
  18. 50 2
      themis-business/src/main/java/com/qmth/themis/business/util/TencentYunUtil.java
  19. 38 0
      themis-business/src/main/resources/mapper/TEExamMapper.xml
  20. 25 0
      themis-business/src/main/resources/mapper/TMTencentVideoMessageMapper.xml
  21. 2 3
      themis-exam/src/main/java/com/qmth/themis/exam/api/TEExamController.java
  22. 2 2
      themis-task/src/main/java/com/qmth/themis/task/quartz/MqActivityJob.java
  23. 3 3
      themis-task/src/main/java/com/qmth/themis/task/quartz/service/impl/QuartzLogicServiceImpl.java

+ 78 - 6
themis-admin/src/main/java/com/qmth/themis/admin/api/SysController.java

@@ -1,8 +1,10 @@
 package com.qmth.themis.admin.api;
 
 import cn.hutool.core.date.DateUtil;
+import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.google.common.reflect.TypeToken;
 import com.qmth.boot.core.solar.config.SolarProperties;
 import com.qmth.boot.core.solar.service.SolarService;
@@ -10,15 +12,13 @@ import com.qmth.themis.admin.config.DictionaryConfig;
 import com.qmth.themis.business.bean.admin.DataCountBean;
 import com.qmth.themis.business.bean.admin.MapDataCountBean;
 import com.qmth.themis.business.bean.admin.OrgDataCountBean;
+import com.qmth.themis.business.bean.result.VideoQueryResult;
 import com.qmth.themis.business.constant.SystemConstant;
 import com.qmth.themis.business.dto.AuthDto;
 import com.qmth.themis.business.dto.response.RoomCodeQueryDto;
 import com.qmth.themis.business.dto.response.TEExamQueryDto;
 import com.qmth.themis.business.entity.*;
-import com.qmth.themis.business.enums.DownloadFileEnum;
-import com.qmth.themis.business.enums.InvigilateMonitorStatusEnum;
-import com.qmth.themis.business.enums.RoleEnum;
-import com.qmth.themis.business.enums.UploadFileEnum;
+import com.qmth.themis.business.enums.*;
 import com.qmth.themis.business.service.*;
 import com.qmth.themis.business.util.*;
 import com.qmth.themis.common.enums.ExceptionResultEnum;
@@ -40,11 +40,11 @@ import org.springframework.web.bind.annotation.RestController;
 import org.springframework.web.multipart.MultipartFile;
 
 import javax.annotation.Resource;
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
 import java.io.File;
 import java.io.IOException;
 import java.util.*;
-import java.util.function.Function;
-import java.util.stream.Collectors;
 
 /**
  * @Description: 系统信息 前端控制器
@@ -118,6 +118,9 @@ public class SysController {
     @Resource
     SolarProperties solarProperties;
 
+    @Resource
+    TMTencentVideoMessageService tmTencentVideoMessageService;
+
     @ApiOperation(value = "同步机构接口")
     @RequestMapping(value = "/sync/org", method = RequestMethod.POST)
     @ApiResponses({@ApiResponse(code = 200, message = "菜单信息", response = Result.class)})
@@ -541,4 +544,73 @@ public class SysController {
             return ResultUtil.ok(new DataCountBean(orgDataCountBeanList, mapDataCountBeanList));
         }
     }
+
+    @ApiOperation(value = "视频存储查询接口")
+    @RequestMapping(value = "/video/select", method = RequestMethod.POST)
+    @ApiResponses({@ApiResponse(code = 200, message = "超管视频存储查询接口", response = VideoQueryResult.class)})
+    public Result videoSelect(@ApiParam(value = "机构代码") @RequestParam(required = false) String orgCode,
+                              @ApiParam(value = "机构名称") @RequestParam(required = false) String orgName,
+                              @ApiParam(value = "状态,ALL:全部,TRUE:有效,FALSE:已删除") @RequestParam(required = false) VideoTypeEnum type,
+                              @ApiParam(value = "分页页码", required = true) @RequestParam @Min(SystemConstant.PAGE_NUMBER_MIN) int pageNumber,
+                              @ApiParam(value = "分页数", required = true) @RequestParam @Min(SystemConstant.PAGE_SIZE_MIN) @Max(SystemConstant.SELECT_PAGE_SIZE_MAX) int pageSize) {
+        return ResultUtil.ok(teExamService.videoQuery(new Page<>(pageNumber, pageSize), orgCode, orgName, type));
+    }
+
+    @ApiOperation(value = "视频存储删除接口")
+    @RequestMapping(value = "/video/delete", method = RequestMethod.POST)
+    @ApiResponses({@ApiResponse(code = 200, message = "超管视频存储删除接口", response = Result.class)})
+    @Transactional
+    public Result videoDelete(@ApiParam(value = "考试id", required = true) @RequestParam Long examId) {
+        List<TMTencentVideoMessage> tmTencentVideoMessageList = tmTencentVideoMessageService.videoQuery(examId);
+        if (!CollectionUtils.isEmpty(tmTencentVideoMessageList)) {
+            Boolean lock = redisUtil.lock(SystemConstant.REDIS_LOCK_TENCENT_VIDEO_DELETE_PREFIX + examId, SystemConstant.REDIS_LOCK_TENCENT_VIDEO_DELETE_TIME_OUT);
+            if (lock) {
+                try {
+                    Set<Long> tencentVideoMessageIds = new HashSet<>(tmTencentVideoMessageList.size());
+                    for (TMTencentVideoMessage t : tmTencentVideoMessageList) {
+                        tencentVideoMessageIds.add(t.getId());
+                        if (Objects.nonNull(t.getObject()) && !Objects.equals(t.getObject().trim(), "")) {
+                            JSONObject jsonObject = JSONObject.parseObject(t.getObject());
+                            if (Objects.nonNull(jsonObject.get("mediaInfoSet")) && !Objects.equals(jsonObject.getString("mediaInfoSet").trim(), "")) {
+                                JSONArray jsonArray = JSONArray.parseArray(jsonObject.getString("mediaInfoSet"));
+                                for (int i = 0; i < jsonArray.size(); i++) {
+                                    JSONObject object = jsonArray.getJSONObject(i);
+                                    if (Objects.nonNull(object.get("fileId")) && !Objects.equals(object.getString("fileId").trim(), "")) {
+                                        tencentYunUtil.deleteMedia(tencentYunUtil.getSecretId(),
+                                                tencentYunUtil.getSecretKey(),
+                                                tencentYunUtil.getQueryUrl(),
+                                                "",
+                                                tencentYunUtil.getVodAppId(),
+                                                object.getString("fileId"));
+                                    }
+                                }
+                            } else if (Objects.nonNull(jsonObject.get("file_id")) && !Objects.equals(jsonObject.getString("file_id").trim(), "")) {
+                                tencentYunUtil.deleteMedia(tencentYunUtil.getSecretId(),
+                                        tencentYunUtil.getSecretKey(),
+                                        tencentYunUtil.getQueryUrl(),
+                                        "",
+                                        tencentYunUtil.getVodAppId(),
+                                        jsonObject.getString("file_id"));
+                            }
+                        }
+                    }
+                    tmTencentVideoMessageService.removeByIds(tencentVideoMessageIds);
+                    TEExam teExam = teExamService.getById(examId);
+                    Optional.ofNullable(teExam).orElseThrow(() -> new BusinessException(ExceptionResultEnum.EXAM_NO));
+
+                    Long time = System.currentTimeMillis();
+                    teExam.setVideoDelete(false);
+                    teExam.setVideoDeleteTime(time);
+                    teExam.setUpdateTime(time);
+                    teExamService.updateById(teExam);
+                    teExamService.updateExamCacheBean(examId);
+                } finally {
+                    redisUtil.releaseLock(SystemConstant.REDIS_LOCK_TENCENT_VIDEO_DELETE_PREFIX + examId);
+                }
+            } else {
+                throw new BusinessException("该考试批次正在删除视频,请稍候再试");
+            }
+        }
+        return ResultUtil.ok(true);
+    }
 }

+ 5 - 9
themis-admin/src/main/java/com/qmth/themis/admin/api/TEExamController.java

@@ -340,9 +340,7 @@ public class TEExamController {
             throw new BusinessException(ExceptionResultEnum.EXAM_ID_IS_NULL);
         }
         ExamCacheBean examCacheBean = teExamService.getExamCacheBean(id);
-        if (Objects.isNull(examCacheBean)) {
-            throw new BusinessException(ExceptionResultEnum.EXAM_NO);
-        }
+        Optional.ofNullable(examCacheBean).orElseThrow(() -> new BusinessException(ExceptionResultEnum.EXAM_NO));
         return ResultUtil.ok(new TEExamDto(teExamService.cacheConvert(examCacheBean)));
     }
 
@@ -367,9 +365,8 @@ public class TEExamController {
         }
         String name = String.valueOf(mapParameter.get(SystemConstant.NAME));
         ExamCacheBean examCacheBean = teExamService.getExamCacheBean(examId);
-        if (Objects.isNull(examCacheBean)) {
-            throw new BusinessException(ExceptionResultEnum.EXAM_NO);
-        }
+        Optional.ofNullable(examCacheBean).orElseThrow(() -> new BusinessException(ExceptionResultEnum.EXAM_NO));
+
         TEExam teExam = teExamService.cacheConvert(examCacheBean);
         List<TEExamActivity> teExamActivityList = null;
         try {
@@ -514,9 +511,8 @@ public class TEExamController {
         //先查询考试相关信息
         ExamCacheBean examCacheBean = teExamService.getExamCacheBean(id);
         TEExam teExam = teExamService.cacheConvert(examCacheBean);
-        if (Objects.isNull(teExam)) {
-            throw new BusinessException(ExceptionResultEnum.EXAM_NO);
-        }
+        Optional.ofNullable(teExam).orElseThrow(() -> new BusinessException(ExceptionResultEnum.EXAM_NO));
+
         TBTaskHistory tbTaskHistory = null;
         Map<String, Object> transMap = new HashMap<String, Object>();
         try {

+ 2 - 3
themis-admin/src/main/java/com/qmth/themis/admin/api/TEExamPaperController.java

@@ -173,9 +173,8 @@ public class TEExamPaperController {
             transMap.put(SystemConstant.ORG_ID, tbUser.getOrgId());
             //先查询考试相关信息
             ExamCacheBean examCacheBean = teExamService.getExamCacheBean(examId);
-            if (Objects.isNull(examCacheBean)) {
-                throw new BusinessException(ExceptionResultEnum.EXAM_NO);
-            }
+            Optional.ofNullable(examCacheBean).orElseThrow(() -> new BusinessException(ExceptionResultEnum.EXAM_NO));
+
 //            TEExam teExam = teExamService.cacheConvert(examCacheBean);
             transMap.put("objectiveShuffle", objectiveShuffle);
             transMap.put("optionShuffle", optionShuffle);

+ 2 - 3
themis-admin/src/main/java/com/qmth/themis/admin/api/TEExamStudentController.java

@@ -361,9 +361,8 @@ public class TEExamStudentController {
 
             // 先查询考试相关信息
             ExamCacheBean examCacheBean = teExamService.getExamCacheBean(examId);
-            if (Objects.isNull(examCacheBean)) {
-                throw new BusinessException(ExceptionResultEnum.EXAM_NO);
-            }
+            Optional.ofNullable(examCacheBean).orElseThrow(() -> new BusinessException(ExceptionResultEnum.EXAM_NO));
+
             TEExam teExam = teExamService.cacheConvert(examCacheBean);
             transMap.put("mode", teExam.getMode());
             transMap.put(SystemConstant.ORG_ID, teExam.getOrgId());

+ 129 - 0
themis-business/src/main/java/com/qmth/themis/business/bean/result/VideoQueryResult.java

@@ -0,0 +1,129 @@
+package com.qmth.themis.business.bean.result;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.io.Serializable;
+
+/**
+ * @Description: 视频result
+ * @Param:
+ * @return:
+ * @Author: wangliang
+ * @Date: 2023/5/4
+ */
+public class VideoQueryResult implements Serializable {
+
+    @JsonSerialize(using = ToStringSerializer.class)
+    @ApiModelProperty(value = "机构id")
+    private Long orgId;
+
+    @ApiModelProperty(value = "机构编码")
+    private String orgCode;
+
+    @ApiModelProperty(value = "机构名称")
+    private String orgName;
+
+    @JsonSerialize(using = ToStringSerializer.class)
+    @ApiModelProperty(value = "考试id")
+    private Long examId;
+
+    @ApiModelProperty(value = "考试编码")
+    private String examCode;
+
+    @ApiModelProperty(value = "考试名称")
+    private String examName;
+
+    @ApiModelProperty(value = "考试结束时间")
+    private Long examEndTime;
+
+    @ApiModelProperty(value = "视频是否删除,0:已删除,1:未删除")
+    private Boolean videoDelete;
+
+    @ApiModelProperty(value = "视频删除时间")
+    private Long videoDeleteTime;
+
+    @ApiModelProperty(value = "存储时长")
+    private Integer saveTime;
+
+    public Long getOrgId() {
+        return orgId;
+    }
+
+    public void setOrgId(Long orgId) {
+        this.orgId = orgId;
+    }
+
+    public String getOrgCode() {
+        return orgCode;
+    }
+
+    public void setOrgCode(String orgCode) {
+        this.orgCode = orgCode;
+    }
+
+    public String getOrgName() {
+        return orgName;
+    }
+
+    public void setOrgName(String orgName) {
+        this.orgName = orgName;
+    }
+
+    public Long getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Long examId) {
+        this.examId = examId;
+    }
+
+    public String getExamCode() {
+        return examCode;
+    }
+
+    public void setExamCode(String examCode) {
+        this.examCode = examCode;
+    }
+
+    public String getExamName() {
+        return examName;
+    }
+
+    public void setExamName(String examName) {
+        this.examName = examName;
+    }
+
+    public Long getExamEndTime() {
+        return examEndTime;
+    }
+
+    public void setExamEndTime(Long examEndTime) {
+        this.examEndTime = examEndTime;
+    }
+
+    public Boolean getVideoDelete() {
+        return videoDelete;
+    }
+
+    public void setVideoDelete(Boolean videoDelete) {
+        this.videoDelete = videoDelete;
+    }
+
+    public Long getVideoDeleteTime() {
+        return videoDeleteTime;
+    }
+
+    public void setVideoDeleteTime(Long videoDeleteTime) {
+        this.videoDeleteTime = videoDeleteTime;
+    }
+
+    public Integer getSaveTime() {
+        return saveTime;
+    }
+
+    public void setSaveTime(Integer saveTime) {
+        this.saveTime = saveTime;
+    }
+}

+ 6 - 2
themis-business/src/main/java/com/qmth/themis/business/constant/SystemConstant.java

@@ -460,10 +460,12 @@ public class SystemConstant {
 
     public static final String REDIS_LOCK_TENCENT_VIDEO_PREFIX = "lock:tencent:video:";//腾讯云视频锁
 
-    public static final String REDIS_LOCK_TENCENT_VIDEO_STREAM_ID_PREFIX = "lock:tencent:video:stream:id";//腾讯云视频锁
+    public static final String REDIS_LOCK_TENCENT_VIDEO_DELETE_PREFIX = "lock:tencent:video:delete:";//腾讯云视频锁
+
+    public static final String REDIS_LOCK_TENCENT_VIDEO_STREAM_ID_PREFIX = "lock:tencent:video:stream:id:";//腾讯云视频锁
 
     //考生锁
-    public static final String REDIS_LOCK_PROBLEM_PREFIX = "lock:problem:id_";
+//    public static final String REDIS_LOCK_PROBLEM_PREFIX = "lock:problem:id_";
 
     /**
      * redis过期时间
@@ -480,6 +482,8 @@ public class SystemConstant {
 
     public static final long REDIS_LOCK_TENCENT_VIDEO_STREAM_ID_TIME_OUT = 60L * 20;
 
+    public static final long REDIS_LOCK_TENCENT_VIDEO_DELETE_TIME_OUT = 60L * 60;
+
     /**
      * rocket mq
      */

+ 12 - 0
themis-business/src/main/java/com/qmth/themis/business/dao/TEExamMapper.java

@@ -3,6 +3,7 @@ package com.qmth.themis.business.dao;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.qmth.themis.business.bean.admin.OpenExamBean;
+import com.qmth.themis.business.bean.result.VideoQueryResult;
 import com.qmth.themis.business.dto.response.TEExamQueryDto;
 import com.qmth.themis.business.dto.response.TEExamWaitDto;
 import com.qmth.themis.business.entity.TEExam;
@@ -87,4 +88,15 @@ public interface TEExamMapper extends BaseMapper<TEExam> {
     public void updateScoreProgress(@Param("progress") Double progress, @Param("examId") Long examId);
 
     public IPage<OpenExamBean> examQueryForOpen(IPage<OpenExamBean> iPage, @Param("id") Long id, @Param("code") String code);
+
+    /**
+     * 视频存储查询接口
+     *
+     * @param iPage
+     * @param orgCode
+     * @param orgName
+     * @param type
+     * @return
+     */
+    public IPage<VideoQueryResult> videoQuery(IPage<Map> iPage, @Param("orgCode") String orgCode, @Param("orgName") String orgName, @Param("type") String type);
 }

+ 10 - 0
themis-business/src/main/java/com/qmth/themis/business/dao/TMTencentVideoMessageMapper.java

@@ -2,6 +2,9 @@ package com.qmth.themis.business.dao;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.qmth.themis.business.entity.TMTencentVideoMessage;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
 
 /**
  * <p>
@@ -13,4 +16,11 @@ import com.qmth.themis.business.entity.TMTencentVideoMessage;
  */
 public interface TMTencentVideoMessageMapper extends BaseMapper<TMTencentVideoMessage> {
 
+    /**
+     * 根据考试批次id查询视频信息
+     *
+     * @param examId
+     * @return
+     */
+    public List<TMTencentVideoMessage> videoQuery(@Param("examId") Long examId);
 }

+ 22 - 0
themis-business/src/main/java/com/qmth/themis/business/entity/TEExam.java

@@ -217,6 +217,12 @@ public class TEExam extends BaseEntity {
     @ApiModelProperty(value = "是否推送违纪考生,false:否,true:是")
     private Boolean examStudentBreachPush = false;
 
+    @ApiModelProperty(value = "视频是否删除,0:已删除,1:未删除")
+    private Boolean videoDelete;
+
+    @ApiModelProperty(value = "视频删除时间")
+    private Long videoDeleteTime;
+
     public TEExam() {
 
     }
@@ -298,6 +304,22 @@ public class TEExam extends BaseEntity {
         this.examStudentCallEnable = teExamDto.getExamStudentCallEnable();
     }
 
+    public Long getVideoDeleteTime() {
+        return videoDeleteTime;
+    }
+
+    public void setVideoDeleteTime(Long videoDeleteTime) {
+        this.videoDeleteTime = videoDeleteTime;
+    }
+
+    public Boolean getVideoDelete() {
+        return videoDelete;
+    }
+
+    public void setVideoDelete(Boolean videoDelete) {
+        this.videoDelete = videoDelete;
+    }
+
     public Integer getExamStudentCallEnable() {
         return examStudentCallEnable;
     }

+ 44 - 0
themis-business/src/main/java/com/qmth/themis/business/enums/VideoTypeEnum.java

@@ -0,0 +1,44 @@
+package com.qmth.themis.business.enums;
+
+import java.util.Objects;
+
+/**
+ * @Description: 音频类型
+ * @Param:
+ * @return:
+ * @Author: wangliang
+ * @Date: 2022/8/30
+ */
+public enum VideoTypeEnum {
+
+    ALL("全部"),
+
+    TRUE("有效"),
+
+    FALSE("已删除");
+
+    VideoTypeEnum(String title) {
+        this.title = title;
+    }
+
+    private String title;
+
+    public String getTitle() {
+        return title;
+    }
+
+    /**
+     * 状态转换 toName
+     *
+     * @param value
+     * @return
+     */
+    public static String convertToName(String value) {
+        for (VideoTypeEnum e : VideoTypeEnum.values()) {
+            if (Objects.equals(value.trim(), e.getTitle())) {
+                return e.name();
+            }
+        }
+        return null;
+    }
+}

+ 1 - 1
themis-business/src/main/java/com/qmth/themis/business/service/CommonService.java

@@ -23,5 +23,5 @@ public interface CommonService {
      *
      * @param recordId
      */
-    public void DismissRoomByStrRoomId(Long recordId);
+    public void dismissRoomByStrRoomId(Long recordId);
 }

+ 13 - 0
themis-business/src/main/java/com/qmth/themis/business/service/TEExamService.java

@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.qmth.themis.business.bean.admin.OpenExamBean;
 import com.qmth.themis.business.bean.exam.*;
+import com.qmth.themis.business.bean.result.VideoQueryResult;
 import com.qmth.themis.business.cache.bean.ExamCacheBean;
 import com.qmth.themis.business.dto.MqDto;
 import com.qmth.themis.business.dto.response.TEExamQueryDto;
@@ -13,6 +14,7 @@ import com.qmth.themis.business.entity.TEExam;
 import com.qmth.themis.business.enums.InvigilateMonitorStatusEnum;
 import com.qmth.themis.business.enums.ScoreStatusEnum;
 import com.qmth.themis.business.enums.SystemOperationEnum;
+import com.qmth.themis.business.enums.VideoTypeEnum;
 import org.springframework.web.multipart.MultipartFile;
 
 import java.util.List;
@@ -233,4 +235,15 @@ public interface TEExamService extends IService<TEExam> {
      * @return
      */
     public TEExam cacheConvert(ExamCacheBean examCacheBean);
+
+    /**
+     * 视频存储查询接口
+     *
+     * @param iPage
+     * @param orgCode
+     * @param orgName
+     * @param type
+     * @return
+     */
+    public IPage<VideoQueryResult> videoQuery(IPage<Map> iPage, String orgCode, String orgName, VideoTypeEnum type);
 }

+ 10 - 0
themis-business/src/main/java/com/qmth/themis/business/service/TMTencentVideoMessageService.java

@@ -3,6 +3,8 @@ package com.qmth.themis.business.service;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.qmth.themis.business.entity.TMTencentVideoMessage;
 
+import java.util.List;
+
 /**
  * <p>
  * 腾讯云视频回调消息 服务类
@@ -19,4 +21,12 @@ public interface TMTencentVideoMessageService extends IService<TMTencentVideoMes
      * @param tencentVideoMessage
      */
     public void saveAndCount(TMTencentVideoMessage tencentVideoMessage);
+
+    /**
+     * 根据考试批次id查询视频信息
+     *
+     * @param examId
+     * @return
+     */
+    public List<TMTencentVideoMessage> videoQuery(Long examId);
 }

+ 2 - 2
themis-business/src/main/java/com/qmth/themis/business/service/impl/CommonServiceImpl.java

@@ -145,9 +145,9 @@ public class CommonServiceImpl implements CommonService {
      * @param recordId
      */
     @Override
-    public void DismissRoomByStrRoomId(Long recordId) {
+    public void dismissRoomByStrRoomId(Long recordId) {
         try {
-            tencentYunUtil.DismissRoomByStrRoomId(tencentYunUtil.getSecretId(),
+            tencentYunUtil.dismissRoomByStrRoomId(tencentYunUtil.getSecretId(),
                     tencentYunUtil.getSecretKey(),
                     tencentYunUtil.getTrtcQueryUrl(),
                     tencentYunUtil.getTrtcRegion(),

+ 16 - 1
themis-business/src/main/java/com/qmth/themis/business/service/impl/TEExamServiceImpl.java

@@ -9,6 +9,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.qmth.themis.business.bean.admin.OpenExamBean;
 import com.qmth.themis.business.bean.exam.*;
+import com.qmth.themis.business.bean.result.VideoQueryResult;
 import com.qmth.themis.business.cache.ExamBreakCacheUtil;
 import com.qmth.themis.business.cache.ExamRecordCacheUtil;
 import com.qmth.themis.business.cache.ExamingDataCacheUtil;
@@ -1270,7 +1271,7 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
         }
 
         //解散房间
-        tencentYunUtil.DismissRoomByStrRoomId(tencentYunUtil.getSecretId(),
+        tencentYunUtil.dismissRoomByStrRoomId(tencentYunUtil.getSecretId(),
                 tencentYunUtil.getSecretKey(),
                 tencentYunUtil.getTrtcQueryUrl(),
                 tencentYunUtil.getTrtcRegion(),
@@ -1627,4 +1628,18 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
     public TEExam cacheConvert(ExamCacheBean examCacheBean) {
         return GsonUtil.fromJson(GsonUtil.toJson(examCacheBean), TEExam.class);
     }
+
+    /**
+     * 视频存储查询接口
+     *
+     * @param iPage
+     * @param orgCode
+     * @param orgName
+     * @param type
+     * @return
+     */
+    @Override
+    public IPage<VideoQueryResult> videoQuery(IPage<Map> iPage, String orgCode, String orgName, VideoTypeEnum type) {
+        return teExamMapper.videoQuery(iPage, orgCode, orgName, Objects.nonNull(type) ? type.name() : null);
+    }
 }

+ 17 - 0
themis-business/src/main/java/com/qmth/themis/business/service/impl/TMTencentVideoMessageServiceImpl.java

@@ -7,6 +7,9 @@ import com.qmth.themis.business.entity.TMTencentVideoMessage;
 import com.qmth.themis.business.service.TMTencentVideoMessageService;
 import org.springframework.stereotype.Service;
 
+import javax.annotation.Resource;
+import java.util.List;
+
 /**
  * <p>
  * 腾讯云视频回调消息 服务实现类
@@ -18,6 +21,9 @@ import org.springframework.stereotype.Service;
 @Service
 public class TMTencentVideoMessageServiceImpl extends ServiceImpl<TMTencentVideoMessageMapper, TMTencentVideoMessage> implements TMTencentVideoMessageService {
 
+    @Resource
+    TMTencentVideoMessageMapper tmTencentVideoMessageMapper;
+
     /**
      * 保存视频
      *
@@ -35,4 +41,15 @@ public class TMTencentVideoMessageServiceImpl extends ServiceImpl<TMTencentVideo
             this.save(tencentVideoMessage);
         }
     }
+
+    /**
+     * 根据考试批次id查询视频信息
+     *
+     * @param examId
+     * @return
+     */
+    @Override
+    public List<TMTencentVideoMessage> videoQuery(Long examId) {
+        return tmTencentVideoMessageMapper.videoQuery(examId);
+    }
 }

+ 2 - 3
themis-business/src/main/java/com/qmth/themis/business/templete/impl/TaskExamPaperImportTemplete.java

@@ -109,9 +109,8 @@ public class TaskExamPaperImportTemplete implements TaskImportTemplete {
 
         Long examId = (Long) map.get(SystemConstant.EXAM_ID);
         ExamCacheBean examCacheBean = teExamService.getExamCacheBean(examId);
-        if (Objects.isNull(examCacheBean)) {
-            throw new BusinessException(ExceptionResultEnum.EXAM_NO);
-        }
+        Optional.ofNullable(examCacheBean).orElseThrow(() -> new BusinessException(ExceptionResultEnum.EXAM_NO));
+
         TEExam teExam = teExamService.cacheConvert(examCacheBean);
         String tempDir = SystemConstant.TEMP_FILES_DIR;
         String dir = tempDir + "/" + SystemConstant.getNanoId() + "/";

+ 50 - 2
themis-business/src/main/java/com/qmth/themis/business/util/TencentYunUtil.java

@@ -4,8 +4,8 @@ import com.qmth.themis.business.constant.SystemConstant;
 import com.qmth.themis.business.entity.SysConfig;
 import com.qmth.themis.business.entity.TOeExamRecord;
 import com.qmth.themis.business.enums.MonitorVideoSourceEnum;
-import com.qmth.themis.business.service.ThemisCacheService;
 import com.qmth.themis.business.service.TGErrorService;
+import com.qmth.themis.business.service.ThemisCacheService;
 import com.qmth.themis.common.exception.BusinessException;
 import com.tencentcloudapi.common.Credential;
 import com.tencentcloudapi.common.exception.TencentCloudSDKException;
@@ -15,6 +15,8 @@ import com.tencentcloudapi.trtc.v20190722.TrtcClient;
 import com.tencentcloudapi.trtc.v20190722.models.DismissRoomByStrRoomIdRequest;
 import com.tencentcloudapi.trtc.v20190722.models.DismissRoomByStrRoomIdResponse;
 import com.tencentcloudapi.vod.v20180717.VodClient;
+import com.tencentcloudapi.vod.v20180717.models.DeleteMediaRequest;
+import com.tencentcloudapi.vod.v20180717.models.DeleteMediaResponse;
 import com.tencentcloudapi.vod.v20180717.models.SearchMediaRequest;
 import com.tencentcloudapi.vod.v20180717.models.SearchMediaResponse;
 import com.tencentyun.TLSSigAPIv2;
@@ -238,7 +240,7 @@ public class TencentYunUtil {
      * @param roomId
      * @return
      */
-    public Map<String, Object> DismissRoomByStrRoomId(String secretId, String secretKey, String endPoint, String region, Long appId, String roomId) {
+    public Map<String, Object> dismissRoomByStrRoomId(String secretId, String secretKey, String endPoint, String region, Long appId, String roomId) {
         log.info("腾讯云解散房间进来了");
         Map<String, Object> resultMap = null;
         try {
@@ -272,6 +274,52 @@ public class TencentYunUtil {
         return resultMap;
     }
 
+    /**
+     * 腾讯云删除媒体文件进来了
+     *
+     * @param secretId
+     * @param secretKey
+     * @param endPoint
+     * @param region
+     * @param subAppId
+     * @param fileId
+     * @return
+     */
+    public Map<String, Object> deleteMedia(String secretId, String secretKey, String endPoint, String region, Long subAppId, String fileId) {
+        log.info("腾讯云删除媒体文件进来了");
+        Map<String, Object> resultMap = null;
+        try {
+            // 实例化一个认证对象,入参需要传入腾讯云账户 SecretId 和 SecretKey,此处还需注意密钥对的保密
+            // 代码泄露可能会导致 SecretId 和 SecretKey 泄露,并威胁账号下所有资源的安全性。以下代码示例仅供参考,建议采用更安全的方式来使用密钥,请参见:https://cloud.tencent.com/document/product/1278/85305
+            // 密钥可前往官网控制台 https://console.cloud.tencent.com/cam/capi 进行获取
+            Credential cred = new Credential(secretId, secretKey);
+            // 实例化一个http选项,可选的,没有特殊需求可以跳过
+            HttpProfile httpProfile = new HttpProfile();
+            httpProfile.setEndpoint(endPoint);
+            // 实例化一个client选项,可选的,没有特殊需求可以跳过
+            ClientProfile clientProfile = new ClientProfile();
+            clientProfile.setHttpProfile(httpProfile);
+            // 实例化要请求产品的client对象,clientProfile是可选的
+            VodClient client = new VodClient(cred, region, clientProfile);
+            // 实例化一个请求对象,每个接口都会对应一个request对象
+            DeleteMediaRequest req = new DeleteMediaRequest();
+            req.setFileId(fileId);
+            req.setSubAppId(subAppId);
+            // 返回的resp是一个DeleteMediaResponse的实例,与请求对象对应
+            DeleteMediaResponse resp = client.DeleteMedia(req);
+            if (Objects.nonNull(resp)) {
+                resultMap = new HashMap<>();
+                // 输出json格式的字符串回包
+                String result = DeleteMediaResponse.toJsonString(resp);
+                resultMap.put("object", resp);
+                log.info("result:{}", result);
+            }
+        } catch (TencentCloudSDKException e) {
+            log.error(SystemConstant.LOG_ERROR, e);
+        }
+        return resultMap;
+    }
+
     public String getAppId() {
         return appId;
     }

+ 38 - 0
themis-business/src/main/resources/mapper/TEExamMapper.xml

@@ -276,9 +276,47 @@
             AND t.code = #{code}
         </if>
     </select>
+
     <update id="updateScoreProgress">
         update t_e_exam
         set progress=#{progress}
         where id = #{examId}
     </update>
+
+    <select id="videoQuery" resultType="com.qmth.themis.business.bean.result.VideoQueryResult">
+        SELECT
+            tbo.id as orgId,
+            tbo.code as orgCode,
+            tbo.name as orgName,
+            tee.id as examId,
+            tee.code as examCode,
+            tee.name as examName,
+            tee.end_time as examEndTime,
+            tee.video_delete as videoDelete,
+            tee.video_delete_time as videoDeleteTime,
+            datediff(now(),FROM_UNIXTIME(tee.end_time / 1000,'%Y-%m-%d %H:%i:%s')) as saveTime
+        from
+            t_e_exam tee
+                join t_b_org tbo on
+                tbo.id = tee.org_id
+        <where> 1 = 1
+            <if test="orgCode != null and orgCode !=''">
+                and tbo.code = #{orgCode}
+            </if>
+            <if test="orgName != null and orgName !=''">
+                and tbo.name like concat('%', #{orgName}, '%')
+            </if>
+            <if test="type != null and type != '' and type != 'ALL'">
+                <choose>
+                    <when test="type == 'TRUE'">
+                        and tee.video_delete = 1
+                    </when>
+                    <otherwise>
+                        and tee.video_delete = 0
+                    </otherwise>
+                </choose>
+            </if>
+        </where>
+        order by tee.end_time
+    </select>
 </mapper>

+ 25 - 0
themis-business/src/main/resources/mapper/TMTencentVideoMessageMapper.xml

@@ -2,4 +2,29 @@
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.qmth.themis.business.dao.TMTencentVideoMessageMapper">
 
+    <select id="videoQuery" resultType="com.qmth.themis.business.entity.TMTencentVideoMessage">
+        select
+            *
+        from
+            t_m_tencent_video_message tmtvm
+        where
+            EXISTS (
+                    select
+                        toer.id
+                    from
+                        t_oe_exam_record toer
+                    where
+                        EXISTS (
+                                SELECT
+                                    x.id
+                                FROM
+                                    t_e_exam x
+                                <where> 1 = 1
+                                    <if test="examId != null and examId !=''">
+                                        and x.id = #{examId}
+                                    </if>
+                                </where>
+                                  and toer.exam_id = x.id)
+                      and tmtvm.exam_record_id = toer.id);
+    </select>
 </mapper>

+ 2 - 3
themis-exam/src/main/java/com/qmth/themis/exam/api/TEExamController.java

@@ -77,9 +77,8 @@ public class TEExamController {
         QueryWrapper<TEExam> teExamQueryWrapper = new QueryWrapper<>();
         teExamQueryWrapper.lambda().eq(TEExam::getShortCode, shortCode).eq(TEExam::getEnable, 1);
         TEExam teExam = teExamService.getOne(teExamQueryWrapper);
-        if (Objects.isNull(teExam)) {
-            throw new BusinessException(ExceptionResultEnum.EXAM_NO);
-        }
+        Optional.ofNullable(teExam).orElseThrow(() -> new BusinessException(ExceptionResultEnum.EXAM_NO));
+
         Map<String, Object> map = new HashMap<>();
         map.put(SystemConstant.ID, teExam.getId());
         map.put(SystemConstant.NAME, teExam.getName());

+ 2 - 2
themis-task/src/main/java/com/qmth/themis/task/quartz/MqActivityJob.java

@@ -102,7 +102,7 @@ public class MqActivityJob extends QuartzJobBean {
                                                 s.setClientWebsocketStatus(WebsocketStatusEnum.OFF_LINE);
                                             }
                                             updateExamRecordList.add(s);
-                                            commonService.DismissRoomByStrRoomId(s.getId());
+                                            commonService.dismissRoomByStrRoomId(s.getId());
                                         } else {//交卷
                                             teExamService.finish(examStudentCacheBean.getStudentId(), s.getId(), FinishTypeEnum.AUTO.name(), durationSeconds);
                                         }
@@ -139,7 +139,7 @@ public class MqActivityJob extends QuartzJobBean {
                                                 s.setClientWebsocketStatus(WebsocketStatusEnum.OFF_LINE);
                                             }
                                             updateExamRecordList.add(s);
-                                            commonService.DismissRoomByStrRoomId(s.getId());
+                                            commonService.dismissRoomByStrRoomId(s.getId());
                                         } else {//交卷
                                             teExamService.finish(examStudentCacheBean.getStudentId(), s.getId(), FinishTypeEnum.AUTO.name(), durationSeconds);
                                         }

+ 3 - 3
themis-task/src/main/java/com/qmth/themis/task/quartz/service/impl/QuartzLogicServiceImpl.java

@@ -89,7 +89,7 @@ public class QuartzLogicServiceImpl implements QuartzLogicService {
                                         s.setClientWebsocketStatus(WebsocketStatusEnum.OFF_LINE);
                                     }
                                     updateExamRecordList.add(s);
-                                    commonService.DismissRoomByStrRoomId(s.getId());
+                                    commonService.dismissRoomByStrRoomId(s.getId());
                                 } else {//交卷
                                     Long recordEndTime = s.getEndTime();
                                     if (Objects.nonNull(examActivityCacheBean.getFinishTime()) && Objects.nonNull(recordEndTime) && examActivityCacheBean.getFinishTime().longValue() == recordEndTime.longValue()) {
@@ -131,7 +131,7 @@ public class QuartzLogicServiceImpl implements QuartzLogicService {
                                             s.setClientWebsocketStatus(WebsocketStatusEnum.OFF_LINE);
                                         }
                                         updateExamRecordList.add(s);
-                                        commonService.DismissRoomByStrRoomId(s.getId());
+                                        commonService.dismissRoomByStrRoomId(s.getId());
                                     } else {//交卷
                                         teExamService.finish(examStudentCacheBean.getStudentId(), s.getId(), FinishTypeEnum.AUTO.name(), durationSeconds);
                                     }
@@ -185,7 +185,7 @@ public class QuartzLogicServiceImpl implements QuartzLogicService {
                     if (Objects.nonNull(tOeExamRecord.getClientWebsocketStatus()) && tOeExamRecord.getClientWebsocketStatus() == WebsocketStatusEnum.ON_LINE) {
                         tOeExamRecord.setClientWebsocketStatus(WebsocketStatusEnum.OFF_LINE);
                     }
-                    commonService.DismissRoomByStrRoomId(recordId);
+                    commonService.dismissRoomByStrRoomId(recordId);
                 } else {//交卷
                     Long recordEndTime = ExamRecordCacheUtil.getEndTime(recordId);
                     if (examActivityCacheBean.getFinishTime().longValue() == recordEndTime.longValue()) {