From daf7acb4f107a427e4a83ba1eb26e5e6012cbdaf Mon Sep 17 00:00:00 2001
From: kongzy <kongzy>
Date: 星期三, 26 六月 2024 17:04:52 +0800
Subject: [PATCH] update

---
 exam-common/src/main/java/com/gkhy/exam/common/enums/PhaseLevelEnum.java                   |   32 +
 exam-admin/src/main/java/com/gkhy/exam/admin/app/AppQuestionBankController.java            |    6 
 exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExStudentServiceImpl.java      |   32 
 exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExCourseServiceImpl.java       |    1 
 exam-system/src/main/resources/mapper/system/SysCompanyMapper.xml                          |  102 +++
 exam-admin/src/main/java/com/gkhy/exam/admin/system/SysNoticeController.java               |    4 
 exam-admin/src/main/java/com/gkhy/exam/admin/web/ExCourseController.java                   |    5 
 exam-system/src/main/resources/mapper/system/ExExamPaperMapper.xml                         |    1 
 exam-admin/src/main/java/com/gkhy/exam/admin/system/SysCommonController.java               |   14 
 exam-system/src/main/java/com/gkhy/exam/system/domain/ExResource.java                      |    4 
 exam-system/src/main/java/com/gkhy/exam/system/domain/vo/CompanyStatisticVO.java           |   39 +
 exam-admin/src/main/java/com/gkhy/exam/admin/web/ExStudentStudyController.java             |    5 
 exam-system/src/main/java/com/gkhy/exam/system/domain/vo/CompanyPhaseStudentVO.java        |   18 
 exam-system/src/main/java/com/gkhy/exam/system/mapper/SysCompanyMapper.java                |   19 
 exam-admin/src/main/java/com/gkhy/exam/admin/app/AppStudentAnswerController.java           |    2 
 exam-admin/src/main/java/com/gkhy/exam/admin/web/ExCoursePhaseController.java              |    4 
 exam-admin/src/main/java/com/gkhy/exam/admin/system/SysDictDataController.java             |    4 
 exam-admin/src/main/java/com/gkhy/exam/admin/system/SysDictTypeController.java             |    5 
 exam-admin/src/main/java/com/gkhy/exam/admin/web/ExCourseChapterPeriodController.java      |    4 
 exam-common/src/main/java/com/gkhy/exam/common/config/FilePathConfig.java                  |   31 +
 exam-system/src/main/java/com/gkhy/exam/system/service/impl/SysCommonServiceImpl.java      |  113 +++
 exam-admin/src/main/java/com/gkhy/exam/admin/web/ExStatisticController.java                |   48 +
 exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExStatisticServiceImpl.java    |  108 +++
 exam-admin/src/main/java/com/gkhy/exam/admin/app/AppQuestionController.java                |   10 
 exam-admin/src/main/java/com/gkhy/exam/admin/web/ExPhaseStudentController.java             |    5 
 exam-common/src/main/java/com/gkhy/exam/common/config/ThreadPoolConfig.java                |    7 
 exam-system/src/main/java/com/gkhy/exam/system/domain/ExQuestion.java                      |    1 
 exam-system/src/main/java/com/gkhy/exam/system/service/ExExamRecordService.java            |   73 ++
 exam-system/src/main/resources/mapper/system/ExPaperStudentMapper.xml                      |    1 
 .gitignore                                                                                 |    3 
 exam-system/src/main/java/com/gkhy/exam/system/domain/vo/CompanyPhaseVO.java               |   18 
 exam-common/src/main/java/com/gkhy/exam/common/utils/MinioUtils.java                       |   41 +
 pom.xml                                                                                    |    8 
 exam-common/pom.xml                                                                        |    4 
 exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExExamRecordServiceImpl.java   |   94 +++
 exam-admin/src/main/java/com/gkhy/exam/admin/app/AppExerciseAnswerController.java          |    2 
 exam-admin/src/main/java/com/gkhy/exam/admin/web/ExExamRecordController.java               |   73 ++
 exam-system/src/main/java/com/gkhy/exam/system/domain/ExExamRecord.java                    |   97 +++
 exam-admin/src/main/java/com/gkhy/exam/admin/web/ExResourceController.java                 |    8 
 exam-admin/src/main/java/com/gkhy/exam/admin/system/SysCompanyController.java              |    5 
 exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExResourceServiceImpl.java     |   53 +
 exam-admin/src/main/java/com/gkhy/exam/admin/web/ExCourseChapterController.java            |    5 
 exam-system/src/main/java/com/gkhy/exam/system/domain/vo/CompanyPaperStudentVO.java        |   18 
 exam-admin/src/main/java/com/gkhy/exam/admin/app/AppPhaseStudentController.java            |    3 
 exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExQuestionServiceImpl.java     |   49 +
 exam-admin/src/main/java/com/gkhy/exam/admin/web/ExQuestionController.java                 |    7 
 exam-admin/src/main/java/com/gkhy/exam/admin/web/ExExamPaperController.java                |    5 
 exam-admin/src/main/java/com/gkhy/exam/admin/system/SysUserController.java                 |    6 
 exam-admin/src/main/java/com/gkhy/exam/admin/web/ExPaperStudentController.java             |   24 
 exam-system/src/main/java/com/gkhy/exam/system/service/ExPaperStudentService.java          |    5 
 exam-admin/src/main/java/com/gkhy/exam/admin/system/SysCarouselController.java             |    4 
 exam-admin/src/main/java/com/gkhy/exam/admin/web/ExStudentController.java                  |    8 
 exam-system/src/main/java/com/gkhy/exam/system/mapper/ExExamRecordMapper.java              |   32 +
 exam-system/src/main/java/com/gkhy/exam/system/service/ExStatisticService.java             |   12 
 exam-admin/src/main/java/com/gkhy/exam/admin/app/AppStudentStudyController.java            |    3 
 exam-admin/src/main/java/com/gkhy/exam/admin/web/ExQuestionBankController.java             |    4 
 exam-admin/src/main/java/com/gkhy/exam/admin/system/SysCategoryController.java             |    4 
 exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExPaperStudentServiceImpl.java |   51 +
 exam-admin/src/main/java/com/gkhy/exam/admin/app/AppResourceController.java                |    2 
 /dev/null                                                                                  |   20 
 exam-admin/src/main/java/com/gkhy/exam/admin/web/ExCompanyPeriodController.java            |   17 
 exam-admin/src/main/java/com/gkhy/exam/admin/app/AppPaperStudentController.java            |    3 
 exam-common/src/main/java/com/gkhy/exam/common/utils/M3u8Utils.java                        |  165 +++++
 exam-system/src/main/java/com/gkhy/exam/system/service/SysCommonService.java               |   39 +
 exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExQuestionBankServiceImpl.java |   46 +
 exam-system/src/main/resources/mapper/system/ExExamRecordMapper.xml                        |   48 +
 exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExExamPaperServiceImpl.java    |   26 
 exam-system/src/test/java/com/gkhy/exam/system/MybatisPlusGenerator.java                   |    2 
 exam-admin/src/main/java/com/gkhy/exam/admin/system/SysProfileController.java              |    3 
 69 files changed, 1,605 insertions(+), 110 deletions(-)

diff --git a/.gitignore b/.gitignore
index 3748198..5f46f96 100644
--- a/.gitignore
+++ b/.gitignore
@@ -32,4 +32,5 @@
 ### VS Code ###
 .vscode/
 logs/
-images/
\ No newline at end of file
+images/
+upload/
\ No newline at end of file
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppExerciseAnswerController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppExerciseAnswerController.java
index afeca6f..fc35d52 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppExerciseAnswerController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppExerciseAnswerController.java
@@ -7,6 +7,7 @@
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
@@ -28,6 +29,7 @@
     @Autowired
     private ExExerciseAnswerService exerciseAnswerService;
 
+    @PreAuthorize("hasAnyAuthority('train:exam:student')")
     @ApiOperation(value = "新增答题")
     @PostMapping
     public CommonResult add(@Validated @RequestBody ExExerciseAnswer exerciseAnswer){
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppPaperStudentController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppPaperStudentController.java
index 800b644..f9f71ab 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppPaperStudentController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppPaperStudentController.java
@@ -9,6 +9,7 @@
 import io.swagger.annotations.ApiImplicitParams;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
 /**
@@ -26,6 +27,7 @@
     @Autowired
     private ExPaperStudentService paperStudentService;
 
+    @PreAuthorize("hasAnyAuthority('train:exam:student')")
     @ApiOperation(value = "分页获取学员的试卷列表(分页)")
     @ApiImplicitParams({
             @ApiImplicitParam(paramType = "query", name = "pageNum", dataType = "int", required = false, value = "当前页,默认1"),
@@ -55,6 +57,7 @@
 //    }
 
 
+    @PreAuthorize("hasAnyAuthority('train:exam:student')")
     @ApiOperation(value = "结束考试")
     @ApiImplicitParams({
             @ApiImplicitParam(paramType = "body", name = "paperId", dataType = "long", required = true, value = "试卷id"),
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppPhaseStudentController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppPhaseStudentController.java
index f959c5b..515568d 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppPhaseStudentController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppPhaseStudentController.java
@@ -9,6 +9,7 @@
 import io.swagger.annotations.ApiImplicitParams;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestParam;
@@ -29,6 +30,7 @@
     @Autowired
     private ExPhaseStudentService phaseStudentService;
 
+    @PreAuthorize("hasAnyAuthority('train:exam:student')")
     @ApiOperation(value = "分页获取学员的批次列表(分页)")
     @ApiImplicitParams({
             @ApiImplicitParam(paramType = "query", name = "pageNum", dataType = "int", required = false, value = "当前页,默认1"),
@@ -39,6 +41,7 @@
         return CommonResult.success(phaseStudentService.selectPhaseStudentListForStudent(phaseStudent));
     }
 
+    @PreAuthorize("hasAnyAuthority('train:exam:student')")
     @ApiOperation(value = "根据id查询学员批次信息")
     @GetMapping(value = { "/getPhaseStudentById" })
     public CommonResult getPhaseStudentById(@RequestParam(value = "phaseStudentId", required = true) Long phaseStudentId)
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppQuestionBankController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppQuestionBankController.java
index 92b2a1f..a74f3bb 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppQuestionBankController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppQuestionBankController.java
@@ -1,6 +1,7 @@
 package com.gkhy.exam.admin.app;
 
 
+import com.gkhy.exam.common.annotation.RepeatSubmit;
 import com.gkhy.exam.common.api.CommonResult;
 import com.gkhy.exam.system.domain.ExQuestionBank;
 import com.gkhy.exam.system.service.ExQuestionBankService;
@@ -9,6 +10,7 @@
 import io.swagger.annotations.ApiImplicitParams;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
 /**
@@ -26,6 +28,7 @@
     @Autowired
     private ExQuestionBankService questionBankService;
 
+    @PreAuthorize("hasAnyAuthority('train:exam:student')")
     @ApiOperation(value = "题库列表(分页)")
     @ApiImplicitParams({
             @ApiImplicitParam(paramType = "query", name = "pageNum", dataType = "int", required = false, value = "当前页,默认1"),
@@ -36,6 +39,7 @@
         return CommonResult.success(questionBankService.selectQuestionBankListForStudent(questionBank));
     }
 
+    @PreAuthorize("hasAnyAuthority('train:exam:student')")
     @ApiOperation(value = "根据id获取题库信息")
     @GetMapping(value = { "/{bankId}" })
     public CommonResult getQuestionBankInfo(@PathVariable(value = "bankId", required = true) Long bankId)
@@ -43,6 +47,8 @@
         return CommonResult.success(questionBankService.selectQuestionBankByIdForStudent(bankId));
     }
 
+    @RepeatSubmit
+    @PreAuthorize("hasAnyAuthority('train:exam:student')")
     @ApiOperation(value = "清除刷题记录")
     @GetMapping(value = { "/clearExerciseRecord" })
     public CommonResult clearExerciseRecord(@RequestParam(value = "bankId", required = true) Long bankId)
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppQuestionController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppQuestionController.java
index 5043de1..79b0722 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppQuestionController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppQuestionController.java
@@ -8,6 +8,7 @@
 import io.swagger.annotations.ApiImplicitParams;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestParam;
@@ -30,7 +31,7 @@
     @Autowired
     private ExQuestionService questionService;
 
-
+    @PreAuthorize("hasAnyAuthority('train:exam:student')")
     @ApiOperation(value = "刷题获取题目ID列表")
     @ApiImplicitParams({
             @ApiImplicitParam(paramType = "query", name = "bankId", dataType = "long", required = false, value = "题库id"),
@@ -42,7 +43,7 @@
         return CommonResult.success(questionService.getExerciseQuestionList(bankId,exerciseType));
     }
 
-
+    @PreAuthorize("hasAnyAuthority('train:exam:student')")
     @ApiOperation(value = "刷题根据题目ID获取题目详情")
     @ApiImplicitParams({
             @ApiImplicitParam(paramType = "query", name = "questionId", dataType = "long", required = true, value = "题目id")
@@ -53,6 +54,7 @@
         return CommonResult.success(questionService.getExerciseQuestionById(questionId));
     }
 
+    @PreAuthorize("hasAnyAuthority('train:exam:student')")
     @ApiOperation(value = "刷题根据题目ID列表批量获取题目详情")
     @ApiImplicitParams({
             @ApiImplicitParam(paramType = "query", name = "questionIds", dataType = "list", required = true, value = "题目id列表")
@@ -64,6 +66,7 @@
     }
 
 
+    @PreAuthorize("hasAnyAuthority('train:exam:student')")
     @ApiOperation(value = "刷题获取错题题目ID列表")
     @ApiImplicitParams({
             @ApiImplicitParam(paramType = "query", name = "bankId", dataType = "long", required = false, value = "题库id")
@@ -75,6 +78,7 @@
     }
 
 
+    @PreAuthorize("hasAnyAuthority('train:exam:student')")
     @ApiOperation(value = "考试获取题目ID列表(考试完成返回错对,未完成则不返回)")
     @ApiImplicitParams({
             @ApiImplicitParam(paramType = "query", name = "bankId", dataType = "long", required = false, value = "考卷id"),
@@ -86,6 +90,7 @@
         return CommonResult.success(questionService.getPaperQuestionList(paperId,viewType));
     }
 
+    @PreAuthorize("hasAnyAuthority('train:exam:student')")
     @ApiOperation(value = "考试根据题目ID获取题目详情(考试完成返回答案,未完成则不返回)")
     @ApiImplicitParams({
             @ApiImplicitParam(paramType = "query", name = "paperId", dataType = "long", required = true, value = "试卷id"),
@@ -97,6 +102,7 @@
         return CommonResult.success(questionService.getPaperQuestionById(paperId,questionId));
     }
 
+    @PreAuthorize("hasAnyAuthority('train:exam:student')")
     @ApiOperation(value = "考试根据题目ID列表批量获取题目详情")
     @ApiImplicitParams({
             @ApiImplicitParam(paramType = "query", name = "paperId", dataType = "long", required = true, value = "试卷id"),
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppResourceController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppResourceController.java
index db0cfe9..7499f14 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppResourceController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppResourceController.java
@@ -6,6 +6,7 @@
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
 /**
@@ -23,6 +24,7 @@
     @Autowired
     private ExResourceService resourceService;
 
+    @PreAuthorize("hasAnyAuthority('train:exam:student')")
     @ApiOperation(value = "根据课时id获取资源信息")
     @GetMapping(value = { "/getResourceByPeriod" })
     public CommonResult getResourceByPeriod(@RequestParam(value = "periodId", required = true) Long periodId)
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppStudentAnswerController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppStudentAnswerController.java
index f0de947..e622a83 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppStudentAnswerController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppStudentAnswerController.java
@@ -7,6 +7,7 @@
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
@@ -28,6 +29,7 @@
     @Autowired
     private ExStudentAnswerService studentAnswerService;
 
+    @PreAuthorize("hasAnyAuthority('train:exam:student')")
     @ApiOperation(value = "新增答题")
     @PostMapping
     public CommonResult add(@Validated @RequestBody ExStudentAnswer studentAnswer){
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppStudentStudyController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppStudentStudyController.java
index ab6c33b..25ecdc0 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppStudentStudyController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppStudentStudyController.java
@@ -9,6 +9,7 @@
 import io.swagger.annotations.ApiImplicitParams;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
@@ -27,12 +28,14 @@
     @Autowired
     private ExStudentStudyService studentStudyService;
 
+    @PreAuthorize("hasAnyAuthority('train:exam:student')")
     @ApiOperation(value = "新增学习记录")
     @PostMapping
     public CommonResult add(@Validated @RequestBody ExStudentStudy studentStudy){
         return CommonResult.success(studentStudyService.insertStudentStudy(studentStudy));
     }
 
+    @PreAuthorize("hasAnyAuthority('train:exam:student')")
     @ApiOperation(value = "上报学习进度")
     @ApiImplicitParams({
             @ApiImplicitParam(paramType = "body", name = "id", dataType = "long", required = true, value = "学习记录id"),
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysCarouselController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysCarouselController.java
index 6109a86..69f8d5e 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysCarouselController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysCarouselController.java
@@ -2,6 +2,7 @@
 
 
 import com.gkhy.exam.common.annotation.Log;
+import com.gkhy.exam.common.annotation.RepeatSubmit;
 import com.gkhy.exam.common.api.CommonResult;
 import com.gkhy.exam.common.enums.BusinessType;
 import com.gkhy.exam.system.domain.SysCarousel;
@@ -47,6 +48,7 @@
         return CommonResult.success(carouselService.selectCarouselById(carouselId));
     }
 
+    @RepeatSubmit
     @PreAuthorize("hasAnyAuthority('train:exam:system')")
     @Log(title = "轮播图管理", businessType = BusinessType.INSERT)
     @ApiOperation(value = "新增轮播图")
@@ -55,6 +57,7 @@
         return CommonResult.success(carouselService.insertCarousel(carousel));
     }
 
+    @RepeatSubmit
     @PreAuthorize("hasAnyAuthority('train:exam:system')")
     @Log(title = "轮播图管理", businessType = BusinessType.UPDATE)
     @ApiOperation(value = "编辑轮播图")
@@ -63,6 +66,7 @@
         return CommonResult.success(carouselService.updateCarousel(carousel));
     }
 
+    @RepeatSubmit
     @PreAuthorize("hasAnyAuthority('train:exam:system')")
     @Log(title = "轮播图管理", businessType = BusinessType.DELETE)
     @ApiOperation(value = "删除轮播图")
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysCategoryController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysCategoryController.java
index 370e098..3dee02d 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysCategoryController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysCategoryController.java
@@ -2,6 +2,7 @@
 
 
 import com.gkhy.exam.common.annotation.Log;
+import com.gkhy.exam.common.annotation.RepeatSubmit;
 import com.gkhy.exam.common.api.CommonResult;
 import com.gkhy.exam.common.enums.BusinessType;
 import com.gkhy.exam.system.domain.SysCategory;
@@ -39,6 +40,7 @@
         return CommonResult.success(categoryService.selectCategoryById(categoryId));
     }
 
+    @RepeatSubmit
     @Log(title = "课程分类管理", businessType = BusinessType.INSERT)
     @ApiOperation(value = "新增课程分类")
     @PostMapping
@@ -46,6 +48,7 @@
         return CommonResult.success(categoryService.insertCategory(category));
     }
 
+    @RepeatSubmit
     @Log(title = "课程分类管理", businessType = BusinessType.UPDATE)
     @ApiOperation(value = "编辑课程分类")
     @PutMapping
@@ -53,6 +56,7 @@
         return CommonResult.success(categoryService.updateCategory(category));
     }
 
+    @RepeatSubmit
     @Log(title = "课程分类管理", businessType = BusinessType.UPDATE)
     @ApiOperation(value = "删除课程分类")
     @DeleteMapping(value = { "/{categoryId}" })
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysCommonController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysCommonController.java
index b520527..af1a6d8 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysCommonController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysCommonController.java
@@ -1,5 +1,6 @@
 package com.gkhy.exam.admin.system;
 
+import com.gkhy.exam.common.annotation.RepeatSubmit;
 import com.gkhy.exam.common.api.CommonResult;
 import com.gkhy.exam.system.domain.vo.UploadObjectVO;
 import com.gkhy.exam.system.service.SysCommonService;
@@ -16,6 +17,7 @@
     @Autowired
     private SysCommonService commonService;
 
+    @RepeatSubmit
     @ApiOperation(value = "上传图片/文件")
     @PostMapping("/uploadFile")
     public CommonResult<UploadObjectVO> uploadFile(MultipartFile file){
@@ -30,4 +32,16 @@
     }
 
 
+    /**
+     * 整个文件上传
+     * 上传视频文件转m3u8
+     *@param file 文件
+     *@return  String: 路径
+     */
+    @PostMapping("/uploadVideo")
+    public CommonResult uploadVideo(@RequestPart("file") MultipartFile file) throws Exception { ;
+        return CommonResult.success(commonService.uploadVideo2M3u8(file));
+    }
+
+
 }
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysCompanyController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysCompanyController.java
index fce4043..01410ef 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysCompanyController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysCompanyController.java
@@ -2,6 +2,7 @@
 
 
 import com.gkhy.exam.common.annotation.Log;
+import com.gkhy.exam.common.annotation.RepeatSubmit;
 import com.gkhy.exam.common.api.CommonResult;
 import com.gkhy.exam.common.enums.BusinessType;
 import com.gkhy.exam.system.domain.SysCompany;
@@ -49,6 +50,7 @@
         return CommonResult.success(companyService.selectCompanyById(companyId));
     }
 
+    @RepeatSubmit
     @PreAuthorize("hasAnyAuthority('train:exam:system')")
     @Log(title = "企业管理", businessType = BusinessType.INSERT)
     @ApiOperation(value = "新增企业")
@@ -57,6 +59,7 @@
         return CommonResult.success(companyService.insertCompany(company));
     }
 
+    @RepeatSubmit
     @PreAuthorize("hasAnyAuthority('train:exam:system')")
     @Log(title = "企业管理", businessType = BusinessType.UPDATE)
     @ApiOperation(value = "编辑企业")
@@ -65,6 +68,7 @@
         return CommonResult.success(companyService.updateCompany(company));
     }
 
+    @RepeatSubmit
     @PreAuthorize("hasAnyAuthority('train:exam:system')")
     @Log(title = "企业管理", businessType = BusinessType.UPDATE)
     @ApiOperation(value = "删除企业")
@@ -73,6 +77,7 @@
         return CommonResult.success(companyService.deleteCompanyById(companyId));
     }
 
+    @RepeatSubmit
     @PreAuthorize("hasAnyAuthority('train:exam:system')")
     @Log(title = "企业管理", businessType = BusinessType.INSERT)
     @ApiOperation(value = "企业分配课时")
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysDictDataController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysDictDataController.java
index 570d927..6242552 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysDictDataController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysDictDataController.java
@@ -1,6 +1,7 @@
 package com.gkhy.exam.admin.system;
 
 import com.gkhy.exam.common.annotation.Log;
+import com.gkhy.exam.common.annotation.RepeatSubmit;
 import com.gkhy.exam.common.api.CommonResult;
 import com.gkhy.exam.common.domain.entity.SysDictData;
 import com.gkhy.exam.common.enums.BusinessType;
@@ -42,6 +43,7 @@
 
     }
 
+    @RepeatSubmit
     @PreAuthorize("hasAnyAuthority('train:exam:system')")
     @Log(title = "字典数据", businessType = BusinessType.INSERT)
     @ApiOperation(value = "新增字典数据")
@@ -50,6 +52,7 @@
         return CommonResult.success(dictDataServic.insertDictData(dictData));
     }
 
+    @RepeatSubmit
     @PreAuthorize("hasAnyAuthority('train:exam:system')")
     @Log(title = "字典数据", businessType = BusinessType.UPDATE)
     @ApiOperation(value = "编辑字典数据")
@@ -58,6 +61,7 @@
         return CommonResult.success(dictDataServic.updateDictData(dictData));
     }
 
+    @RepeatSubmit
     @PreAuthorize("hasAnyAuthority('train:exam:system')")
     @Log(title = "字典类型", businessType = BusinessType.DELETE)
     @ApiOperation(value = "删除字典数据")
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysDictTypeController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysDictTypeController.java
index e05830e..505c2a3 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysDictTypeController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysDictTypeController.java
@@ -1,6 +1,7 @@
 package com.gkhy.exam.admin.system;
 
 import com.gkhy.exam.common.annotation.Log;
+import com.gkhy.exam.common.annotation.RepeatSubmit;
 import com.gkhy.exam.common.api.CommonResult;
 import com.gkhy.exam.common.domain.entity.SysDictType;
 import com.gkhy.exam.common.enums.BusinessType;
@@ -33,6 +34,7 @@
         return CommonResult.success(dictTypeService.selectDictTypeById(dictId));
     }
 
+    @RepeatSubmit
     @PreAuthorize("hasAnyAuthority('train:exam:system')")
     @Log(title = "字典类型", businessType = BusinessType.INSERT)
     @ApiOperation(value = "新增字典类型")
@@ -41,6 +43,7 @@
         return CommonResult.success(dictTypeService.insertDictType(dictType));
     }
 
+    @RepeatSubmit
     @PreAuthorize("hasAnyAuthority('train:exam:system')")
     @Log(title = "字典类型", businessType = BusinessType.UPDATE)
     @ApiOperation(value = "编辑字典类型")
@@ -49,6 +52,7 @@
         return CommonResult.success(dictTypeService.updateDictType(dictType));
     }
 
+    @RepeatSubmit
     @PreAuthorize("hasAnyAuthority('train:exam:system')")
     @Log(title = "字典类型", businessType = BusinessType.DELETE)
     @ApiOperation(value = "删除字典类型")
@@ -58,6 +62,7 @@
         return CommonResult.success();
     }
 
+    @RepeatSubmit
     @Log(title = "字典类型", businessType = BusinessType.CLEAN)
     @ApiOperation(value = "刷新缓存")
     @DeleteMapping("/refreshCache")
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysNoticeController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysNoticeController.java
index 42e3d18..44f4239 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysNoticeController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysNoticeController.java
@@ -1,6 +1,7 @@
 package com.gkhy.exam.admin.system;
 
 import com.gkhy.exam.common.annotation.Log;
+import com.gkhy.exam.common.annotation.RepeatSubmit;
 import com.gkhy.exam.common.api.CommonResult;
 import com.gkhy.exam.common.enums.BusinessType;
 import com.gkhy.exam.system.domain.SysNotice;
@@ -34,6 +35,7 @@
     }
 
 
+    @RepeatSubmit
     @Log(title = "通知公告", businessType = BusinessType.INSERT)
     @ApiOperation(value = "新增通知公告")
     @PostMapping
@@ -42,6 +44,7 @@
         return CommonResult.success(noticeService.insertNotice(notice));
     }
 
+    @RepeatSubmit
     @Log(title = "通知公告", businessType = BusinessType.UPDATE)
     @ApiOperation(value = "修改通知公告")
     @PutMapping
@@ -50,6 +53,7 @@
         return CommonResult.success(noticeService.updateNotice(notice));
     }
 
+    @RepeatSubmit
     @Log(title = "通知公告", businessType = BusinessType.DELETE)
     @ApiOperation(value = "删除通知公告")
     @DeleteMapping("/{noticeIds}")
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysProfileController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysProfileController.java
index c0c259e..80f6ed3 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysProfileController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysProfileController.java
@@ -2,6 +2,7 @@
 
 import cn.hutool.core.codec.Base64;
 import com.gkhy.exam.common.annotation.Log;
+import com.gkhy.exam.common.annotation.RepeatSubmit;
 import com.gkhy.exam.common.api.CommonResult;
 import com.gkhy.exam.common.domain.entity.SysUser;
 import com.gkhy.exam.common.enums.BusinessType;
@@ -33,6 +34,7 @@
         return CommonResult.success(user);
     }
 
+    @RepeatSubmit
     @Log(title = "个人信息", businessType = BusinessType.UPDATE)
     @PutMapping
     public CommonResult updateProfile(@RequestBody SysUser user)
@@ -54,6 +56,7 @@
         throw new ApiException("修改个人信息异常,请联系管理员");
     }
 
+    @RepeatSubmit
     @Log(title = "个人信息", businessType = BusinessType.UPDATE)
     @ApiImplicitParams({
             @ApiImplicitParam(paramType = "body", name = "oldPassword", dataType = "String", required = true, value = "旧密码"),
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysUserController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysUserController.java
index 07aab8c..50da2fd 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysUserController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysUserController.java
@@ -1,6 +1,7 @@
 package com.gkhy.exam.admin.system;
 
 import com.gkhy.exam.common.annotation.Log;
+import com.gkhy.exam.common.annotation.RepeatSubmit;
 import com.gkhy.exam.common.api.CommonResult;
 import com.gkhy.exam.common.domain.entity.SysUser;
 import com.gkhy.exam.common.enums.BusinessType;
@@ -41,6 +42,7 @@
     }
 
 
+    @RepeatSubmit
     @Log(title = "用户管理", businessType = BusinessType.INSERT)
     @ApiOperation(value = "新增用户")
     @PostMapping
@@ -49,6 +51,7 @@
     }
 
 
+    @RepeatSubmit
     @Log(title = "用户管理", businessType = BusinessType.UPDATE)
     @ApiOperation(value = "编辑用户")
     @PutMapping
@@ -57,6 +60,7 @@
     }
 
 
+    @RepeatSubmit
     @Log(title = "用户管理", businessType = BusinessType.DELETE)
     @ApiOperation(value = "删除用户")
     @PutMapping("/{userId}")
@@ -65,6 +69,7 @@
     }
 
 
+    @RepeatSubmit
     @Log(title = "用户管理", businessType = BusinessType.UPDATE)
     @ApiOperation(value = "重置密码")
     @PutMapping(value = "/resetPwd")
@@ -73,6 +78,7 @@
         return CommonResult.success();
     }
 
+    @RepeatSubmit
     @Log(title = "用户管理", businessType = BusinessType.UPDATE)
     @ApiOperation(value = "修改用户状态")
     @PutMapping(value = "/changeStatus")
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExCompanyPeriodController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExCompanyPeriodController.java
index 5c20194..b3c3740 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExCompanyPeriodController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExCompanyPeriodController.java
@@ -2,6 +2,7 @@
 
 
 import com.gkhy.exam.common.annotation.Log;
+import com.gkhy.exam.common.annotation.RepeatSubmit;
 import com.gkhy.exam.common.api.CommonResult;
 import com.gkhy.exam.common.enums.BusinessType;
 import com.gkhy.exam.system.domain.ExCompanyPeriod;
@@ -39,25 +40,11 @@
     }
 
 
+    @RepeatSubmit
     @Log(title = "企业课时变更记录管理", businessType = BusinessType.UPDATE)
     @ApiOperation(value = "删除企业课时变更记录")
     @DeleteMapping(value = { "/{periodId}" })
     public CommonResult delete(@PathVariable(value = "periodId", required = true) Long periodId){
         return CommonResult.success(companyPeriodService.deleteCompanyPeriodById(periodId));
-    }
-
-
-    /**
-     * <p>
-     * 题库表 前端控制器
-     * </p>
-     *
-     * @author kzy
-     * @since 2024-06-18 10:09:52
-     */
-    @RestController
-    @RequestMapping("/system/ex-question-bank")
-    public static class ExQuestionBankController {
-
     }
 }
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExCourseChapterController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExCourseChapterController.java
index c0db6f9..14644bc 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExCourseChapterController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExCourseChapterController.java
@@ -2,6 +2,7 @@
 
 
 import com.gkhy.exam.common.annotation.Log;
+import com.gkhy.exam.common.annotation.RepeatSubmit;
 import com.gkhy.exam.common.api.CommonResult;
 import com.gkhy.exam.common.enums.BusinessType;
 import com.gkhy.exam.system.domain.ExCourseChapter;
@@ -47,7 +48,7 @@
         return CommonResult.success(courseChapterService.selectChapterById(chapterId));
     }
 
-
+    @RepeatSubmit
     @Log(title = "课程章节管理", businessType = BusinessType.INSERT)
     @ApiOperation(value = "新增章节")
     @PostMapping
@@ -55,6 +56,7 @@
         return CommonResult.success(courseChapterService.insertChapter(courseChapter));
     }
 
+    @RepeatSubmit
     @Log(title = "课程章节管理", businessType = BusinessType.UPDATE)
     @ApiOperation(value = "编辑章节")
     @PutMapping
@@ -62,6 +64,7 @@
         return CommonResult.success(courseChapterService.updateChapter(courseChapter));
     }
 
+    @RepeatSubmit
     @Log(title = "课程章节管理", businessType = BusinessType.UPDATE)
     @ApiOperation(value = "删除章节")
     @DeleteMapping(value = { "/{chapterId}" })
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExCourseChapterPeriodController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExCourseChapterPeriodController.java
index be6edd6..bb9a5f7 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExCourseChapterPeriodController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExCourseChapterPeriodController.java
@@ -2,6 +2,7 @@
 
 
 import com.gkhy.exam.common.annotation.Log;
+import com.gkhy.exam.common.annotation.RepeatSubmit;
 import com.gkhy.exam.common.api.CommonResult;
 import com.gkhy.exam.common.enums.BusinessType;
 import com.gkhy.exam.system.domain.ExCourseChapterPeriod;
@@ -46,6 +47,7 @@
         return CommonResult.success(courseChapterPeriodService.selectPeriodById(periodId));
     }
 
+    @RepeatSubmit
     @Log(title = "课时管理", businessType = BusinessType.INSERT)
     @ApiOperation(value = "新增课时")
     @PostMapping
@@ -53,6 +55,7 @@
         return CommonResult.success(courseChapterPeriodService.insertPeriod(chapterPeriod));
     }
 
+    @RepeatSubmit
     @Log(title = "课时管理", businessType = BusinessType.UPDATE)
     @ApiOperation(value = "编辑课时")
     @PutMapping
@@ -60,6 +63,7 @@
         return CommonResult.success(courseChapterPeriodService.updatePeriod(chapterPeriod));
     }
 
+    @RepeatSubmit
     @Log(title = "课时管理", businessType = BusinessType.UPDATE)
     @ApiOperation(value = "删除课时")
     @DeleteMapping(value = { "/{periodId}" })
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExCourseController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExCourseController.java
index 0a39f3d..eb0ee03 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExCourseController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExCourseController.java
@@ -2,6 +2,7 @@
 
 
 import com.gkhy.exam.common.annotation.Log;
+import com.gkhy.exam.common.annotation.RepeatSubmit;
 import com.gkhy.exam.common.api.CommonResult;
 import com.gkhy.exam.common.enums.BusinessType;
 import com.gkhy.exam.system.domain.ExCourse;
@@ -50,6 +51,7 @@
         return CommonResult.success(courseService.selectApproveCourseList(course));
     }
 
+    @RepeatSubmit
     @ApiOperation(value = "课程审批")
     @ApiImplicitParams({
             @ApiImplicitParam(paramType = "body", name = "id", dataType = "long", required = true, value = "课程id"),
@@ -68,6 +70,7 @@
         return CommonResult.success(courseService.selectCourseById(courseId));
     }
 
+    @RepeatSubmit
     @Log(title = "课程管理", businessType = BusinessType.INSERT)
     @ApiOperation(value = "新增课程")
     @PostMapping
@@ -75,6 +78,7 @@
         return CommonResult.success(courseService.insertCourse(course));
     }
 
+    @RepeatSubmit
     @Log(title = "课程管理", businessType = BusinessType.UPDATE)
     @ApiOperation(value = "编辑课程")
     @PutMapping
@@ -82,6 +86,7 @@
         return CommonResult.success(courseService.updateCourse(course));
     }
 
+    @RepeatSubmit
     @Log(title = "课程管理", businessType = BusinessType.UPDATE)
     @ApiOperation(value = "删除课程")
     @DeleteMapping(value = { "/{courseId}" })
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExCoursePhaseController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExCoursePhaseController.java
index 25d25bb..c32a469 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExCoursePhaseController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExCoursePhaseController.java
@@ -2,6 +2,7 @@
 
 
 import com.gkhy.exam.common.annotation.Log;
+import com.gkhy.exam.common.annotation.RepeatSubmit;
 import com.gkhy.exam.common.api.CommonResult;
 import com.gkhy.exam.common.enums.BusinessType;
 import com.gkhy.exam.system.domain.ExCoursePhase;
@@ -47,6 +48,7 @@
         return CommonResult.success(coursePhaseService.selectCoursePhaseById(phaseId));
     }
 
+    @RepeatSubmit
     @Log(title = "批次管理", businessType = BusinessType.INSERT)
     @ApiOperation(value = "新增批次")
     @PostMapping
@@ -54,6 +56,7 @@
         return CommonResult.success(coursePhaseService.insertCoursePhase(coursePhase));
     }
 
+    @RepeatSubmit
     @Log(title = "批次管理", businessType = BusinessType.UPDATE)
     @ApiOperation(value = "编辑批次")
     @PutMapping
@@ -61,6 +64,7 @@
         return CommonResult.success(coursePhaseService.updateCoursePhase(coursePhase));
     }
 
+    @RepeatSubmit
     @Log(title = "批次管理", businessType = BusinessType.UPDATE)
     @ApiOperation(value = "删除批次")
     @DeleteMapping(value = { "/{phaseId}" })
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExExamPaperController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExExamPaperController.java
index 03bd53c..bfc9df7 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExExamPaperController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExExamPaperController.java
@@ -2,6 +2,7 @@
 
 
 import com.gkhy.exam.common.annotation.Log;
+import com.gkhy.exam.common.annotation.RepeatSubmit;
 import com.gkhy.exam.common.api.CommonResult;
 import com.gkhy.exam.common.enums.BusinessType;
 import com.gkhy.exam.system.domain.ExExamPaper;
@@ -46,6 +47,7 @@
         return CommonResult.success(examPaperService.selectExamPaperById(paperId));
     }
 
+    @RepeatSubmit
     @Log(title = "试卷管理", businessType = BusinessType.INSERT)
     @ApiOperation(value = "新增试卷")
     @PostMapping
@@ -53,6 +55,7 @@
         return CommonResult.success(examPaperService.insertExamPaper(examPaper));
     }
 
+    @RepeatSubmit
     @Log(title = "试卷管理", businessType = BusinessType.UPDATE)
     @ApiOperation(value = "编辑试卷")
     @PutMapping
@@ -60,6 +63,7 @@
         return CommonResult.success(examPaperService.updateExamPaper(examPaper));
     }
 
+    @RepeatSubmit
     @Log(title = "试卷管理", businessType = BusinessType.UPDATE)
     @ApiOperation(value = "删除试卷")
     @DeleteMapping(value = { "/{paperId}" })
@@ -74,6 +78,7 @@
         return CommonResult.success(examPaperService.checkNameUnique(examPaper));
     }
 
+    @RepeatSubmit
     @Log(title = "试卷管理", businessType = BusinessType.UPDATE)
     @ApiImplicitParams({
             @ApiImplicitParam(paramType = "body", name = "id", dataType = "long", required = false, value = "试卷id"),
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExExamRecordController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExExamRecordController.java
new file mode 100644
index 0000000..33b619c
--- /dev/null
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExExamRecordController.java
@@ -0,0 +1,73 @@
+package com.gkhy.exam.admin.web;
+
+
+import com.gkhy.exam.common.annotation.Log;
+import com.gkhy.exam.common.annotation.RepeatSubmit;
+import com.gkhy.exam.common.api.CommonResult;
+import com.gkhy.exam.common.enums.BusinessType;
+import com.gkhy.exam.system.domain.ExExamRecord;
+import com.gkhy.exam.system.service.ExExamRecordService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * <p>
+ * 线下教育登记表 前端控制器
+ * </p>
+ *
+ * @author kzy
+ * @since 2024-06-24 16:16:33
+ */
+@Api(tags = "线下教育登记前端控制器")
+@RestController
+@RequestMapping("/exam-record")
+public class ExExamRecordController {
+    @Autowired
+    private ExExamRecordService examRecordService;
+
+    @ApiOperation(value = "登记列表(分页)")
+    @ApiImplicitParams({
+            @ApiImplicitParam(paramType = "query", name = "pageNum", dataType = "int", required = false, value = "当前页,默认1"),
+            @ApiImplicitParam(paramType = "query", name = "pageSize", dataType = "int", required = false, value = "每页数目,默认10")
+    })
+    @GetMapping("/list")
+    public CommonResult list(ExExamRecord examRecord){
+        return CommonResult.success(examRecordService.selectExamRecordList(examRecord));
+    }
+
+    @ApiOperation(value = "根据id获取登记信息")
+    @GetMapping(value = { "/{recordId}" })
+    public CommonResult getExamRecordInfo(@PathVariable(value = "recordId", required = true) Long recordId)
+    {
+        return CommonResult.success(examRecordService.selectExamRecordById(recordId));
+    }
+
+    @RepeatSubmit
+    @Log(title = "线下教育登记管理", businessType = BusinessType.INSERT)
+    @ApiOperation(value = "新增登记")
+    @PostMapping
+    public CommonResult add(@Validated @RequestBody ExExamRecord examRecord){
+        return CommonResult.success(examRecordService.insertExamRecord(examRecord));
+    }
+
+    @RepeatSubmit
+    @Log(title = "线下教育登记管理", businessType = BusinessType.UPDATE)
+    @ApiOperation(value = "编辑登记")
+    @PutMapping
+    public CommonResult edit(@Validated @RequestBody ExExamRecord examRecord){
+        return CommonResult.success(examRecordService.updateExamRecord(examRecord));
+    }
+
+    @RepeatSubmit
+    @Log(title = "线下教育登记管理", businessType = BusinessType.DELETE)
+    @ApiOperation(value = "删除登记")
+    @DeleteMapping(value = { "/{recordId}" })
+    public CommonResult delete(@PathVariable(value = "recordId", required = true) Long recordId){
+        return CommonResult.success(examRecordService.deleteExamRecordById(recordId));
+    }
+}
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExPaperQuestionController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExPaperQuestionController.java
deleted file mode 100644
index 709ae55..0000000
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExPaperQuestionController.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.gkhy.exam.admin.web;
-
-
-import org.springframework.web.bind.annotation.RequestMapping;
-
-import org.springframework.web.bind.annotation.RestController;
-
-/**
- * <p>
- * 试题 前端控制器
- * </p>
- *
- * @author kzy
- * @since 2024-06-06 13:53:17
- */
-@RestController
-@RequestMapping("/paper-question")
-public class ExPaperQuestionController {
-
-}
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExPaperStudentController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExPaperStudentController.java
index af6c380..20b2a6a 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExPaperStudentController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExPaperStudentController.java
@@ -2,6 +2,7 @@
 
 
 import com.gkhy.exam.common.annotation.Log;
+import com.gkhy.exam.common.annotation.RepeatSubmit;
 import com.gkhy.exam.common.api.CommonResult;
 import com.gkhy.exam.common.enums.BusinessType;
 import com.gkhy.exam.system.domain.ExPaperStudent;
@@ -16,6 +17,7 @@
 
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 
 /**
  * <p>
@@ -35,13 +37,15 @@
     @ApiOperation(value = "考卷下的学员列表(分页)")
     @ApiImplicitParams({
             @ApiImplicitParam(paramType = "query", name = "pageNum", dataType = "int", required = false, value = "当前页,默认1"),
-            @ApiImplicitParam(paramType = "query", name = "pageSize", dataType = "int", required = false, value = "每页数目,默认10")
+            @ApiImplicitParam(paramType = "query", name = "pageSize", dataType = "int", required = false, value = "每页数目,默认10"),
+            @ApiImplicitParam(paramType = "query", name = "paperId", dataType = "long", required = true, value = "考卷id")
     })
     @GetMapping("/list")
     public CommonResult list(ExPaperStudent paperStudent){
         return CommonResult.success(paperStudentService.selectPaperStudentList(paperStudent));
     }
 
+    @RepeatSubmit
     @Log(title = "试卷与学员关系管理", businessType = BusinessType.INSERT)
     @ApiOperation(value = "新增学员")
     @PostMapping
@@ -49,21 +53,29 @@
         return CommonResult.success(paperStudentService.addPaperStudent(paperStudent));
     }
 
-    @Log(title = "试卷与学员关系管理", businessType = BusinessType.UPDATE)
+    @RepeatSubmit
+    @Log(title = "试卷与学员关系管理", businessType = BusinessType.INSERT)
+    @ApiImplicitParams({
+            @ApiImplicitParam(paramType = "body", name = "phaseIds", dataType = "array", required = false, value = "批次id列表"),
+            @ApiImplicitParam(paramType = "query", name = "studentIds", dataType = "array", required = false, value = "学员id列表(批次id和学员id列表只能传一个)"),
+            @ApiImplicitParam(paramType = "query", name = "paperId", dataType = "long", required = true, value = "考卷id")
+    })
     @ApiOperation(value = "批量新增学员")
     @PostMapping("/batchAdd")
-    public CommonResult batchAdd(@Validated @RequestBody List<ExPaperStudent> paperStudents){
-        return CommonResult.success(paperStudentService.batchAddPaperStudent(paperStudents));
+    public CommonResult batchAdd(@RequestBody Map<String,Object> paperStudentMap){
+        return CommonResult.success(paperStudentService.batchAddPaperStudent(paperStudentMap));
     }
 
-    @Log(title = "试卷与学员关系管理", businessType = BusinessType.UPDATE)
+    @RepeatSubmit
+    @Log(title = "试卷与学员关系管理", businessType = BusinessType.DELETE)
     @ApiOperation(value = "删除学员")
     @DeleteMapping(value = { "/{phaseStudentId}" })
     public CommonResult delete(@PathVariable(value = "phaseStudentId", required = true) Long paperStudentId){
         return CommonResult.success(paperStudentService.deletePaperStudent(paperStudentId));
     }
 
-    @Log(title = "试卷与学员关系管理", businessType = BusinessType.UPDATE)
+    @RepeatSubmit
+    @Log(title = "试卷与学员关系管理", businessType = BusinessType.DELETE)
     @ApiOperation(value = "批量删除学员")
     @DeleteMapping(value = { "/batchDelete" })
     public CommonResult batchDelete( List<Long> paperStudentIds){
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExPhaseStudentController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExPhaseStudentController.java
index bdf5d2e..512a48c 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExPhaseStudentController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExPhaseStudentController.java
@@ -2,6 +2,7 @@
 
 
 import com.gkhy.exam.common.annotation.Log;
+import com.gkhy.exam.common.annotation.RepeatSubmit;
 import com.gkhy.exam.common.api.CommonResult;
 import com.gkhy.exam.common.enums.BusinessType;
 import com.gkhy.exam.system.domain.ExPhaseStudent;
@@ -43,6 +44,7 @@
         return CommonResult.success(phaseStudentService.selectPhaseStudentList(phaseStudent));
     }
 
+    @RepeatSubmit
     @Log(title = "批次与学员关系管理", businessType = BusinessType.INSERT)
     @ApiOperation(value = "新增学员")
     @PostMapping
@@ -50,6 +52,7 @@
         return CommonResult.success(phaseStudentService.addPhaseStudent(phaseStudent));
     }
 
+    @RepeatSubmit
     @Log(title = "批次与学员关系管理", businessType = BusinessType.UPDATE)
     @ApiOperation(value = "批量新增学员")
     @PostMapping("/batchAdd")
@@ -57,6 +60,7 @@
         return CommonResult.success(phaseStudentService.batchAddPhaseStudent(phaseStudents));
     }
 
+    @RepeatSubmit
     @Log(title = "批次与学员关系管理", businessType = BusinessType.UPDATE)
     @ApiOperation(value = "删除学员")
     @DeleteMapping(value = { "/{phaseStudentId}" })
@@ -64,6 +68,7 @@
         return CommonResult.success(phaseStudentService.deletePhaseStudent(phaseStudentId));
     }
 
+    @RepeatSubmit
     @Log(title = "批次与学员关系管理", businessType = BusinessType.UPDATE)
     @ApiOperation(value = "批量删除学员")
     @DeleteMapping(value = { "/batchDelete" })
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExQuestionBankController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExQuestionBankController.java
index 8caceb1..e39c890 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExQuestionBankController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExQuestionBankController.java
@@ -2,6 +2,7 @@
 
 
 import com.gkhy.exam.common.annotation.Log;
+import com.gkhy.exam.common.annotation.RepeatSubmit;
 import com.gkhy.exam.common.api.CommonResult;
 import com.gkhy.exam.common.enums.BusinessType;
 import com.gkhy.exam.system.domain.ExQuestionBank;
@@ -46,6 +47,7 @@
         return CommonResult.success(questionBankService.selectQuestionBankById(bankId));
     }
 
+    @RepeatSubmit
     @Log(title = "题库管理", businessType = BusinessType.INSERT)
     @ApiOperation(value = "新增题库")
     @PostMapping
@@ -53,6 +55,7 @@
         return CommonResult.success(questionBankService.insertQuestionBank(questionBank));
     }
 
+    @RepeatSubmit
     @Log(title = "题库管理", businessType = BusinessType.UPDATE)
     @ApiOperation(value = "编辑题库")
     @PutMapping
@@ -60,6 +63,7 @@
         return CommonResult.success(questionBankService.updateQuestionBank(questionBank));
     }
 
+    @RepeatSubmit
     @Log(title = "题库管理", businessType = BusinessType.UPDATE)
     @ApiOperation(value = "删除题库")
     @DeleteMapping(value = { "/{bankId}" })
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExQuestionController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExQuestionController.java
index 8a1905c..f18c2e9 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExQuestionController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExQuestionController.java
@@ -2,6 +2,7 @@
 
 
 import com.gkhy.exam.common.annotation.Log;
+import com.gkhy.exam.common.annotation.RepeatSubmit;
 import com.gkhy.exam.common.api.CommonResult;
 import com.gkhy.exam.common.enums.BusinessType;
 import com.gkhy.exam.system.domain.ExQuestion;
@@ -32,7 +33,8 @@
     @ApiOperation(value = "题目列表(分页)")
     @ApiImplicitParams({
             @ApiImplicitParam(paramType = "query", name = "pageNum", dataType = "int", required = false, value = "当前页,默认1"),
-            @ApiImplicitParam(paramType = "query", name = "pageSize", dataType = "int", required = false, value = "每页数目,默认10")
+            @ApiImplicitParam(paramType = "query", name = "pageSize", dataType = "int", required = false, value = "每页数目,默认10"),
+            @ApiImplicitParam(paramType = "query", name = "bankId", dataType = "long", required = true, value = "题库id")
     })
     @GetMapping("/list")
     public CommonResult list(ExQuestion question){
@@ -47,6 +49,7 @@
         return CommonResult.success(questionService.selectQuestionById(questionId));
     }
 
+    @RepeatSubmit
     @Log(title = "题目管理", businessType = BusinessType.INSERT)
     @ApiOperation(value = "新增题目")
     @PostMapping
@@ -54,6 +57,7 @@
         return CommonResult.success(questionService.insertQuestion(question));
     }
 
+    @RepeatSubmit
     @Log(title = "题目管理", businessType = BusinessType.UPDATE)
     @ApiOperation(value = "编辑题目")
     @PutMapping
@@ -61,6 +65,7 @@
         return CommonResult.success(questionService.updateQuestion(question));
     }
 
+    @RepeatSubmit
     @Log(title = "题目管理", businessType = BusinessType.DELETE)
     @ApiOperation(value = "删除题目")
     @DeleteMapping(value = { "/{questionId}" })
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExResourceController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExResourceController.java
index f123f36..67334d2 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExResourceController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExResourceController.java
@@ -2,6 +2,7 @@
 
 
 import com.gkhy.exam.common.annotation.Log;
+import com.gkhy.exam.common.annotation.RepeatSubmit;
 import com.gkhy.exam.common.api.CommonResult;
 import com.gkhy.exam.common.enums.BusinessType;
 import com.gkhy.exam.system.domain.ExResource;
@@ -46,20 +47,23 @@
         return CommonResult.success(resourceService.selectResourceById(resourceId));
     }
 
+    @RepeatSubmit
     @Log(title = "资源管理", businessType = BusinessType.INSERT)
     @ApiOperation(value = "新增资源")
     @PostMapping
-    public CommonResult add(@Validated @RequestBody ExResource resource){
+    public CommonResult add(@Validated @ModelAttribute  ExResource resource){
         return CommonResult.success(resourceService.insertResource(resource));
     }
 
+    @RepeatSubmit
     @Log(title = "资源管理", businessType = BusinessType.UPDATE)
     @ApiOperation(value = "编辑资源")
     @PutMapping
-    public CommonResult edit(@Validated @RequestBody ExResource resource){
+    public CommonResult edit(@Validated  @ModelAttribute ExResource resource){
         return CommonResult.success(resourceService.updateResource(resource));
     }
 
+    @RepeatSubmit
     @Log(title = "资源管理", businessType = BusinessType.UPDATE)
     @ApiOperation(value = "删除资源")
     @DeleteMapping(value = { "/{resourceId}" })
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExStatisticController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExStatisticController.java
new file mode 100644
index 0000000..6425dfe
--- /dev/null
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExStatisticController.java
@@ -0,0 +1,48 @@
+package com.gkhy.exam.admin.web;
+
+
+import com.gkhy.exam.common.api.CommonResult;
+import com.gkhy.exam.system.service.ExStatisticService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Date;
+
+/**
+ * <p>
+ * 统计前端控制器
+ * </p>
+ *
+ * @author kzy
+ * @since 2024-06-06 13:53:17
+ */
+@Api(tags = "统计记录前端控制器")
+@RestController
+@RequestMapping("/statistic")
+public class ExStatisticController {
+    @Autowired
+    private ExStatisticService statisticService;
+
+    @ApiOperation(value = "企业数据统计")
+    @ApiImplicitParams({
+            @ApiImplicitParam(paramType = "query", name = "pageNum", dataType = "int", required = false, value = "当前页,默认1"),
+            @ApiImplicitParam(paramType = "query", name = "pageSize", dataType = "int", required = false, value = "每页数目,默认10"),
+            @ApiImplicitParam(paramType = "query", name = "startTime", dataType = "string", required = false, value = "开始时间(格式:xxxx-xx-xx 00:00:00)"),
+            @ApiImplicitParam(paramType = "query", name = "endTime", dataType = "string", required = false, value = "结束时间(格式:xxxx-xx-xx 00:00:00)"),
+            @ApiImplicitParam(paramType = "query", name = "companyId", dataType = "long", required = false, value = "企业id"),
+            @ApiImplicitParam(paramType = "query", name = "type", dataType = "int", required = true, value = "1线上教育  2线下教育,默认1")
+    })
+    @GetMapping("/companyStatistic")
+    public CommonResult companyStatistic(@RequestParam(required = false) Date startTime, @RequestParam(required = false) Date endTime, @RequestParam(required = false) Long companyId, @RequestParam(required = true,value = "1") Integer type) {
+        return CommonResult.success(statisticService.companyStatic(companyId, startTime, endTime,type));
+    }
+
+
+}
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExStudentAnswerController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExStudentAnswerController.java
deleted file mode 100644
index 78c6803..0000000
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExStudentAnswerController.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.gkhy.exam.admin.web;
-
-
-import org.springframework.web.bind.annotation.RequestMapping;
-
-import org.springframework.web.bind.annotation.RestController;
-
-/**
- * <p>
- * 学员与考试题目关系表 前端控制器
- * </p>
- *
- * @author kzy
- * @since 2024-06-13 17:47:56
- */
-@RestController
-@RequestMapping("/student-answer")
-public class ExStudentAnswerController {
-
-}
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExStudentController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExStudentController.java
index 0962818..4858712 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExStudentController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExStudentController.java
@@ -2,6 +2,7 @@
 
 
 import com.gkhy.exam.common.annotation.Log;
+import com.gkhy.exam.common.annotation.RepeatSubmit;
 import com.gkhy.exam.common.api.CommonResult;
 import com.gkhy.exam.common.enums.BusinessType;
 import com.gkhy.exam.system.domain.ExStudent;
@@ -11,7 +12,6 @@
 import io.swagger.annotations.ApiImplicitParams;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
@@ -48,6 +48,7 @@
         return CommonResult.success(studentService.selectStudentById(studentId));
     }
 
+    @RepeatSubmit
     @Log(title = "学员管理", businessType = BusinessType.INSERT)
     @ApiOperation(value = "新增学员")
     @PostMapping
@@ -55,6 +56,7 @@
         return CommonResult.success(studentService.insertStudent(student));
     }
 
+    @RepeatSubmit
     @Log(title = "学员管理", businessType = BusinessType.UPDATE)
     @ApiOperation(value = "编辑学员")
     @PutMapping
@@ -62,13 +64,15 @@
         return CommonResult.success(studentService.updateStudent(student));
     }
 
-    @Log(title = "学员管理", businessType = BusinessType.UPDATE)
+    @RepeatSubmit
+    @Log(title = "学员管理", businessType = BusinessType.DELETE)
     @ApiOperation(value = "删除学员")
     @DeleteMapping(value = { "/{studentId}" })
     public CommonResult delete(@PathVariable(value = "studentId", required = true) Long studentId){
         return CommonResult.success(studentService.deleteStudentById(studentId));
     }
 
+    @RepeatSubmit
     @Log(title = "学员管理", businessType = BusinessType.UPDATE)
     @ApiOperation(value = "重置密码")
     @PutMapping(value = "/resetPwd")
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExStudentStudyController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExStudentStudyController.java
index e0b55db..e97ba6f 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExStudentStudyController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExStudentStudyController.java
@@ -2,6 +2,7 @@
 
 
 import com.gkhy.exam.common.annotation.Log;
+import com.gkhy.exam.common.annotation.RepeatSubmit;
 import com.gkhy.exam.common.api.CommonResult;
 import com.gkhy.exam.common.enums.BusinessType;
 import com.gkhy.exam.system.service.ExStudentStudyService;
@@ -20,7 +21,7 @@
  * @author kzy
  * @since 2024-06-06 13:53:17
  */
-@Api(tags = "学员学习记录前端控制器")
+@Api(tags = "学员课程学习记录前端控制器")
 @RestController
 @RequestMapping("/student-study")
 public class ExStudentStudyController {
@@ -37,6 +38,8 @@
         return CommonResult.success(studentStudyService.selectStudyByPhaseAndStundentId(phaseId,studentId));
     }
 
+
+    @RepeatSubmit
     @Log(title = "课程学习记录管理", businessType = BusinessType.DELETE)
     @ApiOperation(value = "删除学习记录")
     @DeleteMapping(value = { "/{studyId}" })
diff --git a/exam-common/pom.xml b/exam-common/pom.xml
index 01eeeb9..4fc1fb9 100644
--- a/exam-common/pom.xml
+++ b/exam-common/pom.xml
@@ -115,6 +115,10 @@
             <groupId>eu.bitwalker</groupId>
             <artifactId>UserAgentUtils</artifactId>
         </dependency>
+        <dependency>
+            <groupId>net.bramp.ffmpeg</groupId>
+            <artifactId>ffmpeg</artifactId>
+        </dependency>
     </dependencies>
 
 </project>
\ No newline at end of file
diff --git a/exam-common/src/main/java/com/gkhy/exam/common/config/FilePathConfig.java b/exam-common/src/main/java/com/gkhy/exam/common/config/FilePathConfig.java
new file mode 100644
index 0000000..2460a99
--- /dev/null
+++ b/exam-common/src/main/java/com/gkhy/exam/common/config/FilePathConfig.java
@@ -0,0 +1,31 @@
+package com.gkhy.exam.common.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * @Author wsl
+ * @Version 1.0
+ */
+@Data
+@Component
+@ConfigurationProperties(prefix = "m3u8.convertor")
+public class FilePathConfig {
+    /**
+    * 文件上传临时路径 (本地文件转换不需要)
+    */
+    private String tempPath = "upload/tmp/";
+
+    /**
+     * m3u8文件转换后,储存的根路径
+     */
+    private String basePath = "upload/m3u8/";
+
+    /**
+     * m3u8文件转换后,储存的根路径
+     */
+    private String bigPath = "upload/big/";
+
+    private String proxy = "m3u8/";
+}
\ No newline at end of file
diff --git a/exam-common/src/main/java/com/gkhy/exam/common/config/ThreadPoolConfig.java b/exam-common/src/main/java/com/gkhy/exam/common/config/ThreadPoolConfig.java
index 5bfeb39..42e8c1c 100644
--- a/exam-common/src/main/java/com/gkhy/exam/common/config/ThreadPoolConfig.java
+++ b/exam-common/src/main/java/com/gkhy/exam/common/config/ThreadPoolConfig.java
@@ -13,13 +13,13 @@
 @Configuration
 public class ThreadPoolConfig {
     //核心线程池大小
-    private int corePoolSize=50;
+    private int corePoolSize=10;
     //最大可创建的线程数
-    private int maxPoolSize=200;
+    private int maxPoolSize=500;
     //队列最大长度
     private int queueCapacity=1000;
     //线程池维护非线程允许的空闲时间
-    private int keepAliveSeconds=300;
+    private int keepAliveSeconds=30;
 
     @Bean(name = "threadPoolTaskExecutor")
     public ThreadPoolTaskExecutor threadPoolTaskExecutor(){
@@ -30,6 +30,7 @@
         executor.setKeepAliveSeconds(keepAliveSeconds);
         // 线程池对拒绝任务(无线程可用)的处理策略
         executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
+        executor.initialize();
         return executor;
     }
 
diff --git a/exam-common/src/main/java/com/gkhy/exam/common/enums/PhaseLevelEnum.java b/exam-common/src/main/java/com/gkhy/exam/common/enums/PhaseLevelEnum.java
new file mode 100644
index 0000000..9bc9a65
--- /dev/null
+++ b/exam-common/src/main/java/com/gkhy/exam/common/enums/PhaseLevelEnum.java
@@ -0,0 +1,32 @@
+package com.gkhy.exam.common.enums;
+
+/**
+ * 批次等级
+ *
+ */
+public enum PhaseLevelEnum
+{
+    COMPANY(1, "公司级"),
+    DEPART(2, "部门级"),
+    WORkSHOP(3, "车间级"),
+    OTHER(4, "其他");
+
+    private final Integer code;
+    private final String info;
+
+    PhaseLevelEnum(Integer code, String info)
+    {
+        this.code = code;
+        this.info = info;
+    }
+
+    public Integer getCode()
+    {
+        return code;
+    }
+
+    public String getInfo()
+    {
+        return info;
+    }
+}
diff --git a/exam-common/src/main/java/com/gkhy/exam/common/utils/M3u8Utils.java b/exam-common/src/main/java/com/gkhy/exam/common/utils/M3u8Utils.java
new file mode 100644
index 0000000..480c611
--- /dev/null
+++ b/exam-common/src/main/java/com/gkhy/exam/common/utils/M3u8Utils.java
@@ -0,0 +1,165 @@
+package com.gkhy.exam.common.utils;
+
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.io.FileUtil;
+import com.gkhy.exam.common.config.FilePathConfig;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import net.bramp.ffmpeg.FFmpeg;
+import net.bramp.ffmpeg.FFmpegExecutor;
+import net.bramp.ffmpeg.FFprobe;
+import net.bramp.ffmpeg.builder.FFmpegBuilder;
+import net.bramp.ffmpeg.probe.FFmpegProbeResult;
+import net.bramp.ffmpeg.probe.FFmpegStream;
+import org.springframework.stereotype.Component;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.annotation.Resource;
+import java.io.File;
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+/**
+ * @Author sirwsl
+ * @Version 1.0
+ */
+@Slf4j
+@Component
+public class M3u8Utils {
+
+    @Resource
+    private FFmpeg ffmpeg;
+
+    @Resource
+    private FFprobe ffprobe;
+
+    @Resource
+    private FilePathConfig filePath;
+
+
+
+    /**
+     * 视频文件转 m3u8
+     * 支持: .mp4 | .flv | .avi | .mov | .wmv | .wav
+     * @param file 视频文件
+     * @return 路径
+     */
+    public String mediaFileToM3u8(MultipartFile file){
+        if (file.isEmpty()) {
+            throw new RuntimeException("未发现文件");
+        }
+        log.info("开始解析视频");
+        long start = System.currentTimeMillis();
+        //临时目录创建
+        String path = new File(System.getProperty("user.dir")).getAbsolutePath();
+        String tempFilePath = path+ filePath.getTempPath();
+        if (!FileUtil.exist(tempFilePath)) {
+            FileUtil.mkdir(tempFilePath);
+        }
+        String filePathName = tempFilePath + file.getOriginalFilename();
+        File dest = new File(filePathName);
+        try {
+            file.transferTo(dest);
+        }catch (Exception e){
+            log.error("视频转m3u8格式存在异常,异常原因e:{}",e.getMessage());
+        }
+        long end = System.currentTimeMillis();
+        log.info("临时文件上传成功......耗时:{} ms", end - start);
+        String m3u8FilePath = localFileToM3u8(filePathName);
+        log.info("视频转换已完成 !");
+        return m3u8FilePath;
+    }
+
+    /**
+     * 本地媒体资源转换
+     * @param filePathName : 文件路径
+     * @return :
+     */
+    @SneakyThrows
+    public String localFileToM3u8(String filePathName) {
+        long startTime = System.currentTimeMillis();
+        final FFmpegProbeResult probe = ffprobe.probe(filePathName);
+        final List<FFmpegStream> streams = probe.getStreams().stream().filter(fFmpegStream -> fFmpegStream.codec_type != null).collect(Collectors.toList());
+        final Optional<FFmpegStream> audioStream = streams.stream().filter(fFmpegStream -> FFmpegStream.CodecType.AUDIO.equals(fFmpegStream.codec_type)).findFirst();
+        final Optional<FFmpegStream> videoStream = streams.stream().filter(fFmpegStream -> FFmpegStream.CodecType.VIDEO.equals(fFmpegStream.codec_type)).findFirst();
+
+        if (!audioStream.isPresent()) {
+            log.error("未发现音频流");
+        }
+        if (!videoStream.isPresent()) {
+            log.error("未发现视频流");
+        }
+        //m3u8文件 存储路径
+        String filePath = generateFilePath(this.filePath.getBasePath());
+        if (!FileUtil.exist(filePath)) {
+            FileUtil.mkdir(filePath);
+        }
+        String mainName = getFileMainName(filePathName);
+        String m3u8FileName = filePath + mainName + ".m3u8";
+
+        //下面这一串参数别乱动,经过调优的,1G视频大概需要10秒左右,如果是大佬随意改
+        //"-vsync", "2", "-c:v", "copy", "-c:a", "copy", "-tune", "fastdecode", "-hls_wrap", "0", "-hls_time", "10", "-hls_list_size", "0", "-threads", "12"
+        FFmpegBuilder builder = new FFmpegBuilder()
+                .setInput(filePathName)
+                .overrideOutputFiles(true)
+                .addOutput(m3u8FileName)//输出文件
+                .setFormat(probe.getFormat().format_name) //"mp4"
+                .setAudioBitRate(audioStream.map(fFmpegStream -> fFmpegStream.bit_rate).orElse(0L))
+                .setAudioChannels(1)
+                .setAudioCodec("aac")        // using the aac codec
+                .setAudioSampleRate(audioStream.get().sample_rate)
+                .setAudioBitRate(audioStream.get().bit_rate)
+                .setStrict(FFmpegBuilder.Strict.STRICT)
+                .setFormat("hls")
+                .setPreset("ultrafast")
+                .addExtraArgs("-vsync", "2", "-c:v", "copy", "-c:a", "copy", "-tune", "fastdecode", "-hls_wrap", "0", "-hls_time", "10", "-hls_list_size", "0", "-threads", "12")
+                .done();
+
+        FFmpegExecutor executor = new FFmpegExecutor(ffmpeg, ffprobe);
+        // Run a one-pass encode
+        executor.createJob(builder).run();
+
+        File dest = new File(filePathName);
+        if (dest.isFile() && dest.exists()) {
+            dest.delete();
+            System.gc();
+            log.warn("临时文件 {}已删除", dest.getName());
+        }
+        long endTime = System.currentTimeMillis();
+        log.info("文件:{} 转换完成!共耗时{} ms", dest.getName(), (endTime - startTime));
+        return m3u8FileName;
+    }
+
+    public static String generateFilePath(String basePath){
+        String temp = basePath;
+        if(StringUtils.isNotBlank(basePath)){
+            if(basePath.endsWith("/")){
+                temp = basePath.substring(0,basePath.lastIndexOf("/"));
+            }
+        }
+        return temp+"/"+generateDateDir()+"/";
+    }
+
+
+    /**
+     *@Description 根据当前时间,生成下级存储目录
+     *@Return
+     */
+    public static String generateDateDir(){
+        LocalDateTime now = LocalDateTime.now();
+        return DateUtil.format(now, "yyyyMMdd/HH/mm/ss");
+    }
+
+    /**
+     *@Description 根据文件全路径,获取文件主名称
+     *@param fullPath 文件全路径(包含文件名)
+     *@Return
+     */
+    public static String getFileMainName(String fullPath){
+        String fileName = FileUtil.getName(fullPath);
+        return fileName.substring(0,fileName.lastIndexOf("."));
+    }
+
+}
\ No newline at end of file
diff --git a/exam-common/src/main/java/com/gkhy/exam/common/utils/MinioUtils.java b/exam-common/src/main/java/com/gkhy/exam/common/utils/MinioUtils.java
index 83c85e2..94aa256 100644
--- a/exam-common/src/main/java/com/gkhy/exam/common/utils/MinioUtils.java
+++ b/exam-common/src/main/java/com/gkhy/exam/common/utils/MinioUtils.java
@@ -6,6 +6,7 @@
 import com.gkhy.exam.common.config.MinioConfig;
 import io.minio.*;
 import io.minio.http.Method;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 import org.springframework.util.FastByteArrayOutputStream;
@@ -13,9 +14,11 @@
 
 import javax.servlet.ServletOutputStream;
 import javax.servlet.http.HttpServletResponse;
+import java.io.InputStream;
 import java.util.Date;
 
 @Component
+@Slf4j
 public class MinioUtils {
     @Autowired
     private MinioClient minioClient;
@@ -27,15 +30,27 @@
      * @return boolean
      */
     public Boolean bucketExists(String bucketName) {
-        Boolean found;
+        Boolean found=false;
         try {
             found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
         } catch (Exception e) {
-            e.printStackTrace();
-            return false;
+            log.error("minio校验bucket失败:{}",e.getMessage());
         }
         return found;
     }
+
+    /**
+     * 文件上传 上传完成后请关闭文件流
+     *
+     * @param fileName 带后缀的文件名 检验日期yyyyMMdd加16位随机码
+     * @param stream   文件流 要上传文件的流
+     */
+    public void fileUploader( String fileName, InputStream stream) throws Exception {
+        PutObjectArgs objectArgs = PutObjectArgs.builder().bucket(minioConfig.getBucketName()).object(fileName).stream(stream,-1,-1).contentType("application/octet-stream").build();
+        // 使用putObject上传一个文件到文件分类
+        minioClient.putObject(objectArgs);
+    }
+
 
     /**
      * 文件上传
@@ -43,7 +58,7 @@
      * @param file 文件
      * @return Boolean
      */
-    public String upload(MultipartFile file) {
+    public String uploadFile(MultipartFile file) {
         String originalFilename = file.getOriginalFilename();
         if (StringUtils.isBlank(originalFilename)){
             throw new RuntimeException();
@@ -56,7 +71,7 @@
             //文件名称相同会覆盖
             minioClient.putObject(objectArgs);
         } catch (Exception e) {
-            e.printStackTrace();
+            log.error("minio上传文件失败:{}",e.getMessage());
             return null;
         }
         return objectName;
@@ -110,4 +125,20 @@
             e.printStackTrace();
         }
     }
+
+    /**
+     * 删除文件
+     * @param fileName
+     * @return
+     */
+    public boolean removeFile(String fileName){
+        try {
+            RemoveObjectArgs removeObjectArgs = RemoveObjectArgs.builder().bucket(minioConfig.getBucketName())
+                    .object(fileName).build();
+            minioClient.removeObject(removeObjectArgs);
+            return true;
+        }catch (Exception e){
+            return false;
+        }
+    }
 }
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/domain/ExExamRecord.java b/exam-system/src/main/java/com/gkhy/exam/system/domain/ExExamRecord.java
new file mode 100644
index 0000000..280ce14
--- /dev/null
+++ b/exam-system/src/main/java/com/gkhy/exam/system/domain/ExExamRecord.java
@@ -0,0 +1,97 @@
+package com.gkhy.exam.system.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 线下教育登记表
+ * </p>
+ *
+ * @author kzy
+ * @since 2024-06-24 16:16:33
+ */
+@Getter
+@Setter
+@TableName("ex_exam_record")
+@ApiModel(value = "ExExamRecord对象", description = "线下教育登记表")
+public class ExExamRecord implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty("主键")
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    @ApiModelProperty("公司id")
+    @TableField("company_id")
+    private Long companyId;
+
+    @ApiModelProperty("学员id")
+    @TableField("student_id")
+    private Long studentId;
+
+    @ApiModelProperty("计划名称")
+    @TableField("plan_name")
+    private String planName;
+
+    @ApiModelProperty("课程名称")
+    @TableField("course_name")
+    private String courseName;
+
+    @ApiModelProperty("培训等级")
+    @TableField("level")
+    private String level;
+
+    @ApiModelProperty("要求课时(分)")
+    @TableField("period")
+    private Integer period;
+
+    @ApiModelProperty("实际课时(分)")
+    @TableField("actual_period")
+    private Integer actualPeriod;
+
+    @ApiModelProperty("考试成绩")
+    @TableField("score")
+    private Integer score;
+
+    @ApiModelProperty("是否合格,0不合格 1合格 默认0")
+    @TableField("passed")
+    private Integer passed;
+
+    @ApiModelProperty("创建时间")
+    @TableField("create_time")
+    private LocalDateTime createTime;
+
+    @ApiModelProperty("创建人")
+    @TableField("create_by")
+    private String createBy;
+
+    @ApiModelProperty("更新时间")
+    @TableField("update_time")
+    private LocalDateTime updateTime;
+
+    @ApiModelProperty("更新人")
+    @TableField("update_by")
+    private String updateBy;
+
+    @ApiModelProperty("备注")
+    @TableField("remark")
+    private String remark;
+
+
+    @ApiModelProperty("公司名称")
+    @TableField(exist = false)
+    private String companyName;
+
+
+}
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/domain/ExQuestion.java b/exam-system/src/main/java/com/gkhy/exam/system/domain/ExQuestion.java
index 274ae63..81e1b50 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/domain/ExQuestion.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/domain/ExQuestion.java
@@ -48,6 +48,7 @@
     @TableField("bank_id")
     private Long bankId;
 
+    @NotNull(message = "公司id不能为空")
     @ApiModelProperty("公司id")
     @TableField("company_id")
     private Long companyId;
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/domain/ExResource.java b/exam-system/src/main/java/com/gkhy/exam/system/domain/ExResource.java
index ec280bf..32581e0 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/domain/ExResource.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/domain/ExResource.java
@@ -13,7 +13,6 @@
 import org.springframework.web.multipart.MultipartFile;
 
 import javax.validation.constraints.NotBlank;
-import javax.validation.constraints.NotEmpty;
 import javax.validation.constraints.NotNull;
 import java.io.Serializable;
 import java.time.LocalDateTime;
@@ -54,7 +53,6 @@
     @TableField("name")
     private String name;
 
-    @NotEmpty(message = "公司id不能为空")
     @ApiModelProperty(value = "提交公司id",required = true)
     @TableField("company_id")
     private Long companyId;
@@ -63,7 +61,7 @@
     @TableField("privatize")
     private Integer privatize;
 
-    @NotBlank(message = "资源种类不能为空")
+    @NotNull(message = "资源种类不能为空")
     @ApiModelProperty(value = "资源种类(1:视频2:音频;3:文档)",required = true)
     @TableField("resource_type")
     private Integer resourceType;
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/domain/vo/CompanyPaperStudentVO.java b/exam-system/src/main/java/com/gkhy/exam/system/domain/vo/CompanyPaperStudentVO.java
new file mode 100644
index 0000000..f0b7373
--- /dev/null
+++ b/exam-system/src/main/java/com/gkhy/exam/system/domain/vo/CompanyPaperStudentVO.java
@@ -0,0 +1,18 @@
+package com.gkhy.exam.system.domain.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+
+@Getter
+@Setter
+@Accessors(chain = true)
+public class CompanyPaperStudentVO {
+    @ApiModelProperty("公司id")
+    private Long companyId;
+    @ApiModelProperty("考试人员数量")
+    private Integer paperStudentCount;
+    @ApiModelProperty("合格人员数量")
+    private Integer passStudentCount;
+}
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/domain/vo/CompanyPhaseStudentVO.java b/exam-system/src/main/java/com/gkhy/exam/system/domain/vo/CompanyPhaseStudentVO.java
new file mode 100644
index 0000000..87e0e5e
--- /dev/null
+++ b/exam-system/src/main/java/com/gkhy/exam/system/domain/vo/CompanyPhaseStudentVO.java
@@ -0,0 +1,18 @@
+package com.gkhy.exam.system.domain.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+
+@Getter
+@Setter
+@Accessors(chain = true)
+public class CompanyPhaseStudentVO {
+    @ApiModelProperty("公司id")
+    private Long companyId;
+    @ApiModelProperty("批次人员数量")
+    private Integer phaseStudentCount;
+    @ApiModelProperty("批次等级")
+    private Integer level;
+}
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/domain/vo/CompanyPhaseVO.java b/exam-system/src/main/java/com/gkhy/exam/system/domain/vo/CompanyPhaseVO.java
new file mode 100644
index 0000000..2346a78
--- /dev/null
+++ b/exam-system/src/main/java/com/gkhy/exam/system/domain/vo/CompanyPhaseVO.java
@@ -0,0 +1,18 @@
+package com.gkhy.exam.system.domain.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+
+@Getter
+@Setter
+@Accessors(chain = true)
+public class CompanyPhaseVO {
+    @ApiModelProperty("公司id")
+    private Long companyId;
+    @ApiModelProperty("批次数量")
+    private Integer phaseCount;
+    @ApiModelProperty("批次等级")
+    private Integer level;
+}
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/domain/vo/CompanyStatisticVO.java b/exam-system/src/main/java/com/gkhy/exam/system/domain/vo/CompanyStatisticVO.java
new file mode 100644
index 0000000..7d221c3
--- /dev/null
+++ b/exam-system/src/main/java/com/gkhy/exam/system/domain/vo/CompanyStatisticVO.java
@@ -0,0 +1,39 @@
+package com.gkhy.exam.system.domain.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+
+@Getter
+@Setter
+@Accessors(chain = true)
+@ApiModel(value = "CompanyStatisticVO对象", description = "公司数据统计对象")
+public class CompanyStatisticVO {
+    @ApiModelProperty("公司id")
+    private Long companyId;
+    @ApiModelProperty("公司名称")
+    private String companyName;
+    @ApiModelProperty("批次数量")
+    private Integer phaseCount;
+    @ApiModelProperty("批次人员数量")
+    private Integer phaseStudentCount;
+    @ApiModelProperty("三级批次数量")
+    private Integer level3PhaseCount;
+    @ApiModelProperty("三级人员数量")
+    private Integer level3StudentCount;
+    @ApiModelProperty("二级批次数量")
+    private Integer level2PhaseCount;
+    @ApiModelProperty("二级人员数量")
+    private Integer level2StudentCount;
+    @ApiModelProperty("一级批次数量")
+    private Integer level1PhaseCount;
+    @ApiModelProperty("一级人员数量")
+    private Integer level1StudentCount;
+
+    @ApiModelProperty("考试人员数量")
+    private Integer paperStudentCount;
+    @ApiModelProperty("合格人员数量")
+    private Integer passStudentCount;
+}
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExExamRecordMapper.java b/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExExamRecordMapper.java
new file mode 100644
index 0000000..591953b
--- /dev/null
+++ b/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExExamRecordMapper.java
@@ -0,0 +1,32 @@
+package com.gkhy.exam.system.mapper;
+
+import com.gkhy.exam.system.domain.ExExamRecord;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 线下教育登记表 Mapper 接口
+ * </p>
+ *
+ * @author kzy
+ * @since 2024-06-24 16:16:33
+ */
+@Mapper
+public interface ExExamRecordMapper extends BaseMapper<ExExamRecord> {
+    /**
+     * 分页获取登记记录列表
+     * @param examRecord
+     * @return
+     */
+    List<ExExamRecord> selectExamRecordList(ExExamRecord examRecord);
+
+    /**
+     * 根据id获取登记记录详情
+     * @param recordId
+     * @return
+     */
+    ExExamRecord selectExamRecordById(Long recordId);
+}
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/mapper/SysCompanyMapper.java b/exam-system/src/main/java/com/gkhy/exam/system/mapper/SysCompanyMapper.java
index f920c61..7bfe3bb 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/mapper/SysCompanyMapper.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/mapper/SysCompanyMapper.java
@@ -2,7 +2,11 @@
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.gkhy.exam.system.domain.SysCompany;
+import com.gkhy.exam.system.domain.vo.CompanyPaperStudentVO;
+import com.gkhy.exam.system.domain.vo.CompanyPhaseStudentVO;
+import com.gkhy.exam.system.domain.vo.CompanyPhaseVO;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
 
 import java.util.List;
 
@@ -47,4 +51,19 @@
      * @return
      */
     SysCompany checkNameUnique(String name);
+
+    List<CompanyPhaseVO> getOnlineCompanyPhaseCount(@Param("companyIds") List<Long> companyIds, @Param("startTime")String startTime, @Param("endTime")String endTime);
+
+    List<CompanyPhaseStudentVO> getOnlineCompanyPhaseStudentCount(@Param("companyIds")List<Long> companyIds,@Param("startTime")String startTime,@Param("endTime")String endTime);
+
+    List<CompanyPaperStudentVO> getOnlineCompanyPaperStudentCount(@Param("companyIds")List<Long> companyIds,@Param("startTime")String startTime,@Param("endTime")String endTime);
+
+
+    List<CompanyPhaseVO> getOfflineCompanyPhaseCount(@Param("companyIds") List<Long> companyIds, @Param("startTime")String startTime, @Param("endTime")String endTime);
+
+    List<CompanyPhaseStudentVO> getOfflineCompanyPhaseStudentCount(@Param("companyIds")List<Long> companyIds,@Param("startTime")String startTime,@Param("endTime")String endTime);
+
+    List<CompanyPaperStudentVO> getOfflineCompanyPaperStudentCount(@Param("companyIds")List<Long> companyIds,@Param("startTime")String startTime,@Param("endTime")String endTime);
+
+
 }
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/service/ExExamRecordService.java b/exam-system/src/main/java/com/gkhy/exam/system/service/ExExamRecordService.java
new file mode 100644
index 0000000..a9b165e
--- /dev/null
+++ b/exam-system/src/main/java/com/gkhy/exam/system/service/ExExamRecordService.java
@@ -0,0 +1,73 @@
+package com.gkhy.exam.system.service;
+
+import com.gkhy.exam.common.api.CommonPage;
+import com.gkhy.exam.system.domain.ExExamRecord;
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.springframework.web.multipart.MultipartFile;
+
+/**
+ * <p>
+ * 线下教育登记表 服务类
+ * </p>
+ *
+ * @author kzy
+ * @since 2024-06-24 16:16:33
+ */
+public interface ExExamRecordService extends IService<ExExamRecord> {
+    /**
+     * 根据条件分页查询登记列表
+     * @param examRecord
+     * @return
+     */
+    CommonPage selectExamRecordList(ExExamRecord examRecord);
+
+
+    /**
+     * 根据id查询登记信息
+     *
+     * @param recordId
+     * @return
+     */
+    public ExExamRecord selectExamRecordById(Long recordId);
+
+
+    /**
+     * 新增登记记录
+     *
+     * @param examRecord
+     * @return 结果
+     */
+    public int insertExamRecord(ExExamRecord examRecord);
+
+
+    /**
+     * 修改登记记录
+     *
+     * @param examRecord
+     * @return 结果
+     */
+    public int updateExamRecord(ExExamRecord examRecord);
+
+    /**
+     * 删除登记记录
+     *
+     * @param recordId
+     * @return 结果
+     */
+    public int deleteExamRecordById(Long recordId);
+
+
+    /**
+     * 校验登记记录是否唯一
+     *
+     * @param examRecord
+     * @return boolean
+     */
+    public boolean checkRecordUnique(ExExamRecord examRecord);
+
+    /**
+     * 导入登记记录
+     */
+    public void importRecord(MultipartFile file);
+
+}
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/service/ExPaperStudentService.java b/exam-system/src/main/java/com/gkhy/exam/system/service/ExPaperStudentService.java
index 99f385e..b76d2b7 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/service/ExPaperStudentService.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/service/ExPaperStudentService.java
@@ -5,6 +5,7 @@
 import com.gkhy.exam.system.domain.ExPaperStudent;
 
 import java.util.List;
+import java.util.Map;
 
 /**
  * <p>
@@ -25,10 +26,10 @@
 
     /**
      * 批量新增考卷与学员关系
-     * @param paperStudents
+     * @param paperStudentMap
      * @return
      */
-    public int batchAddPaperStudent(List<ExPaperStudent> paperStudents);
+    public int batchAddPaperStudent(Map<String,Object> paperStudentMap);
 
     /**
      * 分页获取学员的试卷列表
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/service/ExStatisticService.java b/exam-system/src/main/java/com/gkhy/exam/system/service/ExStatisticService.java
new file mode 100644
index 0000000..4b6235f
--- /dev/null
+++ b/exam-system/src/main/java/com/gkhy/exam/system/service/ExStatisticService.java
@@ -0,0 +1,12 @@
+package com.gkhy.exam.system.service;
+
+import com.gkhy.exam.common.api.CommonPage;
+
+import java.util.Date;
+
+/**
+ * 统计 服务类
+ */
+public interface ExStatisticService {
+    public CommonPage companyStatic(Long companyId, Date startTime, Date  endTime, Integer type);
+}
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/service/SysCommonService.java b/exam-system/src/main/java/com/gkhy/exam/system/service/SysCommonService.java
index 86f6def..e9d5b70 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/service/SysCommonService.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/service/SysCommonService.java
@@ -3,6 +3,8 @@
 import com.gkhy.exam.system.domain.vo.UploadObjectVO;
 import org.springframework.web.multipart.MultipartFile;
 
+import javax.servlet.http.HttpServletRequest;
+
 public interface SysCommonService {
 
     /**
@@ -22,4 +24,41 @@
     UploadObjectVO doUpload(String imageBase64);
 
     public boolean removeFile(String path);
+
+    /**
+     * 删除文件并转成m3u8格式
+     * @param file
+     * @return
+     * @throws Exception
+     */
+    public String uploadVideo2M3u8(MultipartFile file) throws Exception;
+
+    /**
+     * 大文件上传至本地
+     *
+     * @param request :请求
+     * @param guid    : 编码文件名
+     * @param chunk   : 切片数
+     * @param file    : 切片文件
+     * @return : 是否成功
+     */
+    public boolean uploadSlice(HttpServletRequest request, String guid, Integer chunk, MultipartFile file);
+
+    /**
+     * 切片上传后合并转M3U8格式 :
+     * @param fileName :文件名
+     * @param guid: 随机id
+     * @return :
+     */
+    public String uploadVideoMerge(String guid, String fileName);
+
+    /**
+     * 合并切片并上传至服务器
+     * @param guid :
+     * @param fileName :
+     * @return :
+     */
+    public String uploadMerge(String guid, String fileName);
+
+
 }
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExCourseServiceImpl.java b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExCourseServiceImpl.java
index 1f4748c..6b63b4d 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExCourseServiceImpl.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExCourseServiceImpl.java
@@ -76,6 +76,7 @@
         checkUserAllowed(course);
         if(SecurityUtils.getLoginUser().getUser().getUserType().equals(UserTypeEnum.SYSTEM_USER.getCode())){
             course.setState(ApproveStatusEnum.APPROVED.getCode());
+            course.setPrivatize(PrivatizeEnum.PUBLIC.getCode());
         }else{
             course.setState(ApproveStatusEnum.APPROVING.getCode());
         }
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExExamPaperServiceImpl.java b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExExamPaperServiceImpl.java
index a24760b..5bd7e0d 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExExamPaperServiceImpl.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExExamPaperServiceImpl.java
@@ -88,6 +88,8 @@
         examPaper.setCreateBy(SecurityUtils.getUsername());
         if(examPaper.getLimitTime()>0){
             examPaper.setLimit(1);
+        }else{
+            examPaper.setLimit(0);
         }
         int row=baseMapper.insert(examPaper);
         if(row<1){
@@ -135,19 +137,19 @@
     }
 
     private List<ExPaperQuestion> getPaperQuestions(Long paperId,Long bankId,Integer questionMethod,Integer questionCount,Integer questionScore, QuestionTypeEnum questionTypeEnum) {
-        SysUser user=SecurityUtils.getLoginUser().getUser();
-        Integer totalQuestionCount=questionMapper.selectCountByBankId(user.getCompanyId(), bankId, questionTypeEnum.getCode());
+        SysUser currentUser=SecurityUtils.getLoginUser().getUser();
+        Integer totalQuestionCount=questionMapper.selectCountByBankId(currentUser.getCompanyId(), bankId, questionTypeEnum.getCode());
         if(totalQuestionCount< questionCount){
             throw new ApiException(String.format("所选题库<%s>数量不足,无法分配",questionTypeEnum.getInfo()));
         }
         List<ExQuestion> questions=new ArrayList<>();
         if(Objects.equals(questionMethod, QuestionAssignEnum.RANDOM.getCode())){//随机分配
-            questions=questionMapper.selectRandomQuestion(user.getCompanyId(), bankId,questionTypeEnum.getCode(), questionCount);
+            questions=questionMapper.selectRandomQuestion(currentUser.getCompanyId(), bankId,questionTypeEnum.getCode(), questionCount);
         }else{//顺序分配
-            int totalPage=questionCount/ questionMethod;//不能整除,忽略最后一页
+            int totalPage=questionCount/questionMethod;//不能整除,忽略最后一页
             Random random=new Random();
             int startIndex=random.nextInt(totalPage)+1;
-            questions=questionMapper.selectQuestionWithLimit(user.getCompanyId(), bankId,questionTypeEnum.getCode(),startIndex, questionCount);
+            questions=questionMapper.selectQuestionWithLimit(currentUser.getCompanyId(), bankId,questionTypeEnum.getCode(),startIndex, questionCount);
         }
         List<ExPaperQuestion> paperQuestionList=questions.stream().map(item -> {
             ExPaperQuestion exPaperQuestion=new ExPaperQuestion();
@@ -162,6 +164,7 @@
 
     @Override
     public int updateExamPaper(ExExamPaper examPaper) {
+        checkUserAllowed(examPaper);
         if(!checkNameUnique(examPaper)){
             throw new ApiException("试卷名称已存在");
         }
@@ -170,7 +173,9 @@
             throw new ApiException("该试卷下已分配学员,不能编辑");
         }
         examPaper.setCode(null);//编号不能修改
-        if(examPaper.getLimitTime()==0){
+        if(examPaper.getLimitTime()>0){
+            examPaper.setLimit(1);
+        }else{
             examPaper.setLimit(0);
         }
         int row=baseMapper.updateById(examPaper);
@@ -199,16 +204,17 @@
 
     @Override
     public int deleteExamPaperById(Long paperId) {
+        checkUserAllowed(baseMapper.selectById(paperId));
         //查询该试卷分配的学员人数
         if(checkPaperHasStudent(paperId)){
             throw new ApiException("该试卷下已分配学员,不能删除");
         }
-        int row=baseMapper.deleteById(paperId);
+        int row=baseMapper.deletePaperById(paperId);
         if(row<1){
             throw new ApiException("删除试卷失败");
         }
         //删除考卷试题
-        paperQuestionMapper.deletebyPapaerId(paperId);
+     //   paperQuestionMapper.deletebyPapaerId(paperId);
         return row;
     }
 
@@ -233,9 +239,7 @@
 
     @Override
     public int changeExamPaperStatus(Long paperId, Integer status) {
+        checkUserAllowed(baseMapper.selectById(paperId));
         return baseMapper.updateById(new ExExamPaper().setId(paperId).setStatus(status).setUpdateBy(SecurityUtils.getUsername()));
     }
-
-
-
 }
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExExamRecordServiceImpl.java b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExExamRecordServiceImpl.java
new file mode 100644
index 0000000..a0479b9
--- /dev/null
+++ b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExExamRecordServiceImpl.java
@@ -0,0 +1,94 @@
+package com.gkhy.exam.system.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.gkhy.exam.common.api.CommonPage;
+import com.gkhy.exam.common.domain.entity.SysUser;
+import com.gkhy.exam.common.enums.UserTypeEnum;
+import com.gkhy.exam.common.exception.ApiException;
+import com.gkhy.exam.common.utils.PageUtils;
+import com.gkhy.exam.common.utils.SecurityUtils;
+import com.gkhy.exam.system.domain.ExExamRecord;
+import com.gkhy.exam.system.mapper.ExExamRecordMapper;
+import com.gkhy.exam.system.service.ExExamRecordService;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 线下教育登记表 服务实现类
+ * </p>
+ *
+ * @author kzy
+ * @since 2024-06-24 16:16:33
+ */
+@Service
+public class ExExamRecordServiceImpl extends ServiceImpl<ExExamRecordMapper, ExExamRecord> implements ExExamRecordService {
+
+
+    @Override
+    public CommonPage selectExamRecordList(ExExamRecord examRecord) {
+        SysUser user= SecurityUtils.getLoginUser().getUser();
+        if(!user.getUserType().equals(UserTypeEnum.SYSTEM_USER.getCode())){
+            examRecord.setCompanyId(user.getCompanyId());
+        }
+        PageUtils.startPage();
+        List<ExExamRecord> recordList=baseMapper.selectExamRecordList(examRecord);
+        return CommonPage.restPage(recordList);
+    }
+
+    @Override
+    public ExExamRecord selectExamRecordById(Long recordId) {
+        return baseMapper.selectExamRecordById(recordId);
+    }
+
+    @Override
+    public int insertExamRecord(ExExamRecord examRecord) {
+        checkUserAllowed(examRecord);
+        int row=baseMapper.insert(examRecord);
+        if(row<1){
+            throw new ApiException("新增登记记录失败");
+        }
+        return row;
+    }
+
+    @Override
+    public int updateExamRecord(ExExamRecord examRecord) {
+        checkUserAllowed(examRecord);
+        int row=baseMapper.updateById(examRecord);
+        if(row<1){
+            throw new ApiException("更新登记记录失败");
+        }
+        return row;
+    }
+
+    @Override
+    public int deleteExamRecordById(Long recordId) {
+        checkUserAllowed(baseMapper.selectById(recordId));
+        return baseMapper.deleteById(recordId);
+    }
+
+    public void checkUserAllowed(ExExamRecord examRecord) {
+        SysUser currentUser= SecurityUtils.getLoginUser().getUser();
+        if(currentUser.getUserType().equals(UserTypeEnum.SYSTEM_USER.getCode())){
+            return;
+        }
+        if(currentUser.getUserType().equals(UserTypeEnum.STUDENT.getCode())){
+            throw new ApiException("没有权限操作");
+        }
+        if(!currentUser.getCompanyId().equals(examRecord.getCompanyId())){
+            throw new ApiException("没有权限操作其他企业登记记录");
+        }
+    }
+
+    @Override
+    public boolean checkRecordUnique(ExExamRecord examRecord) {
+        return false;
+    }
+
+    @Override
+    public void importRecord(MultipartFile file) {
+
+    }
+}
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExPaperStudentServiceImpl.java b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExPaperStudentServiceImpl.java
index dea8694..a4f1643 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExPaperStudentServiceImpl.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExPaperStudentServiceImpl.java
@@ -1,6 +1,7 @@
 package com.gkhy.exam.system.service.impl;
 
 import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.gkhy.exam.common.api.CommonPage;
 import com.gkhy.exam.common.domain.entity.SysUser;
@@ -11,19 +12,16 @@
 import com.gkhy.exam.common.utils.SecurityUtils;
 import com.gkhy.exam.system.domain.ExExamPaper;
 import com.gkhy.exam.system.domain.ExPaperStudent;
+import com.gkhy.exam.system.domain.ExPhaseStudent;
 import com.gkhy.exam.system.domain.ExStudent;
-import com.gkhy.exam.system.mapper.ExExamPaperMapper;
-import com.gkhy.exam.system.mapper.ExPaperStudentMapper;
-import com.gkhy.exam.system.mapper.ExStudentAnswerMapper;
-import com.gkhy.exam.system.mapper.ExStudentMapper;
+import com.gkhy.exam.system.mapper.*;
 import com.gkhy.exam.system.service.ExPaperStudentService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
+import java.util.*;
+import java.util.stream.Collectors;
 
 /**
  * <p>
@@ -41,6 +39,8 @@
     private ExStudentAnswerMapper studentAnswerMapper;
     @Autowired
     private ExStudentMapper studentMapper;
+    @Autowired
+    private ExPhaseStudentMapper phaseStudentMapper;
 
 
     @Override
@@ -67,6 +67,7 @@
 
     @Override
     public int addPaperStudent(ExPaperStudent paperStudent) {
+        checkUserAllowed(paperStudent);
         checkStudentUnique(Collections.singletonList(paperStudent));
         paperStudent.setCreateId(SecurityUtils.getUserId());
         int row=baseMapper.insert(paperStudent);
@@ -77,7 +78,25 @@
     }
 
     @Override
-    public int batchAddPaperStudent(List<ExPaperStudent> paperStudents) {
+    public int batchAddPaperStudent(Map<String,Object> paperStudentMap) {
+        List<Long> phaseIds= (List<Long>) paperStudentMap.get("phaseIds");
+        List<Long> studentIds= (List<Long>) paperStudentMap.get("studentIds");
+        if(ObjectUtil.isEmpty(phaseIds) && ObjectUtil.isEmpty(studentIds)){
+            throw new ApiException("批次id与学员id不能同时为空");
+        }
+        Long paperId= (Long) paperStudentMap.get("paperId");
+        if(paperId==null){
+            throw new ApiException("考卷id不能为空");
+        }
+        //按批次绑定用户
+        if(phaseIds.size()>0){
+            List<ExPhaseStudent> phaseStudentList=phaseStudentMapper.selectList( Wrappers.<ExPhaseStudent>lambdaQuery()
+                    .in(ExPhaseStudent::getPhaseId, phaseIds));
+            studentIds=phaseStudentList.stream().map(item -> item.getStudentId()).distinct().collect(Collectors.toList());
+        }
+        List<ExPaperStudent> paperStudents=studentIds.stream().map(item -> {
+            return new ExPaperStudent().setPaperId(paperId).setStudentId(item);
+        }).collect(Collectors.toList());
         checkStudentUnique(paperStudents);
         int row=baseMapper.batchInsert(paperStudents);
         if(row<1){
@@ -100,7 +119,7 @@
     @Override
     public CommonPage selectPaperStudentList(ExPaperStudent paperStudent) {
         if(paperStudent.getPaperId()==null){
-            throw new ApiException("试卷id不能为空");
+            throw new ApiException("考卷id不能为空");
         }
         PageUtils.startPage();
         List<ExPaperStudent> paperStudentList=baseMapper.selectPaperStudentList(paperStudent);
@@ -113,6 +132,7 @@
         if(ObjectUtil.isNull(paperStudent)){
             throw new ApiException(String.format("该试卷下不存在该学员<>",paperStudent.getStudentName()));
         }
+        checkUserAllowed(paperStudent);
         int studentAnswerCount=studentAnswerMapper.countByPaperId(paperStudent.getPaperId(),paperStudent.getStudentId());
         if(studentAnswerCount>0){
             throw new ApiException(String.format("学员<%s>已进行答题,不能删除",paperStudent.getStudentName()));
@@ -130,7 +150,20 @@
     }
 
 
+    public void checkUserAllowed(ExPaperStudent paperStudent) {
+        SysUser currentUser= SecurityUtils.getLoginUser().getUser();
+        if(currentUser.getUserType().equals(UserTypeEnum.SYSTEM_USER.getCode())){
+            return;
+        }
+        if(currentUser.getUserType().equals(UserTypeEnum.STUDENT.getCode())){
+            throw new ApiException("没有权限操作");
+        }
+        ExExamPaper examPaper=examPaperMapper.selectById(paperStudent.getPaperId());
+        if(!currentUser.getCompanyId().equals(examPaper.getCompanyId())){
+            throw new ApiException("没有权限操作其他企业考卷");
+        }
 
+    }
 
     @Override
     public void endExam(ExPaperStudent paperStudent) {
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExQuestionBankServiceImpl.java b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExQuestionBankServiceImpl.java
index 0a496b8..8b45914 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExQuestionBankServiceImpl.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExQuestionBankServiceImpl.java
@@ -33,6 +33,10 @@
 
     @Override
     public CommonPage selectQuestionBankList(ExQuestionBank questionBank) {
+        SysUser user= SecurityUtils.getLoginUser().getUser();
+        if(!user.getUserType().equals(UserTypeEnum.SYSTEM_USER.getCode())){
+            questionBank.setCompanyId(user.getCompanyId());
+        }
         PageUtils.startPage();
         List<ExQuestionBank> bankList=baseMapper.selectQuestionBankList(questionBank);
         return CommonPage.restPage(bankList);
@@ -40,11 +44,23 @@
 
     @Override
     public ExQuestionBank selectQuestionBankById(Long bankId) {
-        return baseMapper.selectById(bankId);
+        ExQuestionBank questionBank= baseMapper.selectById(bankId);
+        if(questionBank.getPrivatize().equals(PrivatizeEnum.PUBLIC.getCode())){
+            return questionBank;
+        }
+        SysUser currentUser=SecurityUtils.getLoginUser().getUser();
+        if(currentUser.getUserType().equals(UserTypeEnum.SYSTEM_USER.getCode())){
+            return questionBank;
+        }
+        if(!questionBank.getCompanyId().equals(currentUser.getCompanyId())){
+            throw new ApiException("无权限查看其它企业题库");
+        }
+        return questionBank;
     }
 
     @Override
     public int insertQuestionBank(ExQuestionBank questionBank) {
+        checkUserAllowed(questionBank);
         if(!checkNameUnique(questionBank)){
             throw new ApiException("题库名称已存在");
         }
@@ -52,10 +68,6 @@
         if(user.getUserType().equals(UserTypeEnum.SYSTEM_USER.getCode())){
             questionBank.setPrivatize(PrivatizeEnum.PUBLIC.getCode());
         }else{
-            if(user.getCompanyId()==null){
-                throw new ApiException("获取用户公司id为空");
-            }
-            questionBank.setPrivatize(PrivatizeEnum.PRIVATE.getCode());
             questionBank.setCompanyId(user.getCompanyId());
         }
         int row =baseMapper.insert(questionBank);
@@ -67,6 +79,7 @@
 
     @Override
     public int updateQuestionBank(ExQuestionBank questionBank) {
+        checkUserAllowed(questionBank);
         if(!checkNameUnique(questionBank)){
             throw new ApiException("题库名称已存在");
         }
@@ -77,8 +90,22 @@
         return row;
     }
 
+    public void checkUserAllowed(ExQuestionBank questionBank) {
+        SysUser currentUser= SecurityUtils.getLoginUser().getUser();
+        if(currentUser.getUserType().equals(UserTypeEnum.SYSTEM_USER.getCode())){
+            return;
+        }
+        if(currentUser.getUserType().equals(UserTypeEnum.STUDENT.getCode())){
+            throw new ApiException("没有权限操作");
+        }
+        if(!currentUser.getCompanyId().equals(questionBank.getCompanyId())){
+            throw new ApiException("没有权限操作其他企业课程");
+        }
+    }
+
     @Override
     public int deleteQuestionBankById(Long bankId) {
+        checkUserAllowed(baseMapper.selectById(bankId));
         return baseMapper.deleteByBankId(bankId);
     }
 
@@ -101,6 +128,9 @@
     @Override
     public CommonPage selectQuestionBankListForStudent(ExQuestionBank questionBank) {
         SysUser user= SecurityUtils.getLoginUser().getUser();
+        if(!user.getUserType().equals(UserTypeEnum.STUDENT.getCode())){
+            throw new ApiException("非学员用户,无法查看");
+        }
         questionBank.setCompanyId(user.getCompanyId());
         questionBank.setStudentId(user.getId());
         PageUtils.startPage();
@@ -110,7 +140,11 @@
 
     @Override
     public ExQuestionBank selectQuestionBankByIdForStudent(Long bankId) {
-        return baseMapper.selectQuestionBankByIdForStudent(bankId,SecurityUtils.getUserId());
+        SysUser user= SecurityUtils.getLoginUser().getUser();
+        if(!user.getUserType().equals(UserTypeEnum.STUDENT.getCode())){
+            throw new ApiException("非学员用户,无法查看");
+        }
+        return baseMapper.selectQuestionBankByIdForStudent(bankId,user.getId());
     }
 
     @Override
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExQuestionServiceImpl.java b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExQuestionServiceImpl.java
index 7c6cd3e..809eabf 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExQuestionServiceImpl.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExQuestionServiceImpl.java
@@ -16,8 +16,10 @@
 import com.gkhy.exam.system.domain.ExExamPaper;
 import com.gkhy.exam.system.domain.ExPaperStudent;
 import com.gkhy.exam.system.domain.ExQuestion;
+import com.gkhy.exam.system.domain.ExQuestionBank;
 import com.gkhy.exam.system.mapper.ExExamPaperMapper;
 import com.gkhy.exam.system.mapper.ExPaperStudentMapper;
+import com.gkhy.exam.system.mapper.ExQuestionBankMapper;
 import com.gkhy.exam.system.mapper.ExQuestionMapper;
 import com.gkhy.exam.system.service.ExQuestionService;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -41,11 +43,22 @@
     private ExPaperStudentMapper paperStudentMapper;
     @Autowired
     private ExExamPaperMapper examPaperMapper;
+    @Autowired
+    private ExQuestionBankMapper questionBankMapper;
 
     @Override
     public CommonPage selectQuestionList(ExQuestion question) {
         if(question.getBankId()==null){
             throw new ApiException("题库id不能为空");
+        }
+        ExQuestionBank questionBank=questionBankMapper.selectById(question.getBankId());
+        if(!questionBank.getPrivatize().equals(PrivatizeEnum.PUBLIC.getCode())){
+            SysUser currentUser=SecurityUtils.getLoginUser().getUser();
+            if(!currentUser.getUserType().equals(UserTypeEnum.SYSTEM_USER.getCode())){
+                if(!question.getCompanyId().equals(currentUser.getCompanyId())){
+                    throw new ApiException("无权限查看其它企业题目");
+                }
+            }
         }
         PageUtils.startPage();
         List<ExQuestion> questionList=baseMapper.selectQuestionList(question);
@@ -54,18 +67,29 @@
 
     @Override
     public ExQuestion selectQuestionById(Long questionId) {
-        return baseMapper.selectById(questionId);
+        ExQuestion question= baseMapper.selectById(questionId);
+        if(question.getPrivatize().equals(PrivatizeEnum.PUBLIC.getCode())){
+            return question;
+        }
+        SysUser currentUser=SecurityUtils.getLoginUser().getUser();
+        if(currentUser.getUserType().equals(UserTypeEnum.SYSTEM_USER.getCode())){
+            return question;
+        }
+        if(!question.getCompanyId().equals(currentUser.getCompanyId())){
+            throw new ApiException("无权限查看其它企业题目");
+        }
+        return question;
     }
 
     @Override
     public int insertQuestion(ExQuestion question) {
+        checkUserAllowed(question);
         SysUser user= SecurityUtils.getLoginUser().getUser();
-        if(user.getUserType().equals(UserTypeEnum.SYSTEM_USER.getCode())){
+        //公开的题库新增题目,题目也是公开
+        ExQuestionBank questionBank=questionBankMapper.selectById(question.getBankId());
+        if(user.getUserType().equals(UserTypeEnum.SYSTEM_USER.getCode())||questionBank.getPrivatize().equals(PrivatizeEnum.PUBLIC.getCode())){
             question.setPrivatize(PrivatizeEnum.PUBLIC.getCode());
         }else{
-            if(user.getCompanyId()==null){
-                throw new ApiException("获取用户公司id失败");
-            }
             question.setCompanyId(user.getCompanyId());
             question.setPrivatize(PrivatizeEnum.PRIVATE.getCode());
         }
@@ -80,6 +104,7 @@
     @Override
     public int updateQuestion(ExQuestion question) {
         validData(question);
+        checkUserAllowed(question);
         int row=baseMapper.updateById(question);
         if(row<1){
             throw new ApiException("编辑题目失败");
@@ -108,8 +133,22 @@
         
     }
 
+    public void checkUserAllowed(ExQuestion question) {
+        SysUser currentUser= SecurityUtils.getLoginUser().getUser();
+        if(currentUser.getUserType().equals(UserTypeEnum.SYSTEM_USER.getCode())){
+            return;
+        }
+        if(currentUser.getUserType().equals(UserTypeEnum.STUDENT.getCode())){
+            throw new ApiException("没有权限操作");
+        }
+        if(!currentUser.getCompanyId().equals(question.getCompanyId())){
+            throw new ApiException("没有权限操作其他企业题目");
+        }
+    }
+
     @Override
     public int deleteQuestionById(Long questionId) {
+        checkUserAllowed(baseMapper.selectById(questionId));
         return baseMapper.deleteById(questionId);
     }
 
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExResourceServiceImpl.java b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExResourceServiceImpl.java
index 1defc76..52ebb5b 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExResourceServiceImpl.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExResourceServiceImpl.java
@@ -44,16 +44,46 @@
 
     @Override
     public ExResource selectResourceById(Long resourceId) {
-        return baseMapper.selectResourceById(resourceId);
+        ExResource resource= baseMapper.selectResourceById(resourceId);
+        if(resource==null){
+            return resource;
+        }
+        if(resource.getPrivatize().equals(PrivatizeEnum.PUBLIC.getCode())){
+            return resource;
+        }
+        SysUser currentUser=SecurityUtils.getLoginUser().getUser();
+        if(currentUser.getUserType().equals(UserTypeEnum.SYSTEM_USER.getCode())){
+            return resource;
+        }
+        if(!resource.getCompanyId().equals(currentUser.getCompanyId())){
+            throw new ApiException("无权限查看其它企业资源");
+        }
+        return resource;
     }
 
     @Override
     public ExResource selectResourceByPeriodId(Long periodId) {
-        return baseMapper.selectResourceByPeriodId(periodId);
+        ExResource resource= baseMapper.selectResourceByPeriodId(periodId);
+        if(resource==null){
+            return resource;
+        }
+        if(resource.getPrivatize().equals(PrivatizeEnum.PUBLIC.getCode())){
+            return resource;
+        }
+        SysUser currentUser=SecurityUtils.getLoginUser().getUser();
+        if(currentUser.getUserType().equals(UserTypeEnum.SYSTEM_USER.getCode())){
+            return resource;
+        }
+        if(!resource.getCompanyId().equals(currentUser.getCompanyId())){
+            throw new ApiException("无权限查看其它企业资源");
+        }
+        return resource;
+
     }
 
     @Override
     public int insertResource(ExResource resource) {
+        checkUserAllowed(resource);
         if(!checkNameUnique(resource)){
             throw new ApiException("资源名称已存在");
         }
@@ -61,11 +91,7 @@
         if(user.getUserType().equals(UserTypeEnum.SYSTEM_USER.getCode())){
             resource.setPrivatize(PrivatizeEnum.PUBLIC.getCode());
         }else{
-            if(user.getCompanyId()==null){
-                throw new ApiException("获取用户公司id失败");
-            }
             resource.setCompanyId(user.getCompanyId());
-            resource.setPrivatize(PrivatizeEnum.PRIVATE.getCode());
         }
         UploadObjectVO uploadObjectVO =commonService.doUpload(resource.getFile());
         resource.setResourceUri(uploadObjectVO.getPath());
@@ -87,6 +113,7 @@
 
     @Override
     public int updateResource(ExResource resource) {
+        checkUserAllowed(resource);
         if(!checkNameUnique(resource)){
             throw new ApiException("资源名称已存在");
         }
@@ -97,9 +124,23 @@
         return row;
     }
 
+    public void checkUserAllowed(ExResource resource) {
+        SysUser currentUser= SecurityUtils.getLoginUser().getUser();
+        if(currentUser.getUserType().equals(UserTypeEnum.SYSTEM_USER.getCode())){
+            return;
+        }
+        if(currentUser.getUserType().equals(UserTypeEnum.STUDENT.getCode())){
+            throw new ApiException("没有权限操作");
+        }
+        if(!currentUser.getCompanyId().equals(resource.getCompanyId())){
+            throw new ApiException("没有权限操作其他企业资源");
+        }
+    }
+
     @Override
     public int deleteResourceById(Long resourceId) {
         //校验资源是否绑定
+        checkUserAllowed(baseMapper.selectById(resourceId));
         ExResource resource=getById(resourceId);
         int row=baseMapper.deleteById(resourceId);
         if(row<1){
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExStatisticServiceImpl.java b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExStatisticServiceImpl.java
new file mode 100644
index 0000000..14ae8db
--- /dev/null
+++ b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExStatisticServiceImpl.java
@@ -0,0 +1,108 @@
+package com.gkhy.exam.system.service.impl;
+
+import cn.hutool.core.date.DateUtil;
+import com.gkhy.exam.common.api.CommonPage;
+import com.gkhy.exam.common.domain.entity.SysUser;
+import com.gkhy.exam.common.enums.PhaseLevelEnum;
+import com.gkhy.exam.common.enums.UserTypeEnum;
+import com.gkhy.exam.common.utils.PageUtils;
+import com.gkhy.exam.common.utils.SecurityUtils;
+import com.gkhy.exam.system.domain.SysCompany;
+import com.gkhy.exam.system.domain.vo.CompanyPaperStudentVO;
+import com.gkhy.exam.system.domain.vo.CompanyPhaseStudentVO;
+import com.gkhy.exam.system.domain.vo.CompanyPhaseVO;
+import com.gkhy.exam.system.domain.vo.CompanyStatisticVO;
+import com.gkhy.exam.system.mapper.SysCompanyMapper;
+import com.gkhy.exam.system.service.ExStatisticService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Service
+public class ExStatisticServiceImpl implements ExStatisticService {
+    @Autowired
+    private SysCompanyMapper companyMapper;
+    @Override
+    public CommonPage companyStatic(Long companyId, Date startTime, Date endTime,Integer type) {
+        SysUser user= SecurityUtils.getLoginUser().getUser();
+        if(!user.getUserType().equals(UserTypeEnum.SYSTEM_USER.getCode())){
+            companyId=user.getCompanyId();
+        }
+        PageUtils.startPage();
+        List<SysCompany> companyList=companyMapper.selectCompanyList(new SysCompany().setId(companyId));
+        CommonPage commonPage= CommonPage.restPage(companyList);
+        List<CompanyStatisticVO>companyStatisticVOList=staticData(companyList, DateUtil.formatDateTime(DateUtil.beginOfDay(startTime)),DateUtil.formatDateTime(DateUtil.endOfDay(endTime)),type);
+        commonPage.setList(companyStatisticVOList);
+        return commonPage;
+    }
+
+    public List<CompanyStatisticVO> staticData(List<SysCompany> companyList,String startTime,String endTime,Integer type){
+        List<Long> companyIds=companyList.stream().map(item -> item.getId()).collect(Collectors.toList());
+
+        List<CompanyPhaseVO> companyPhaseVOList=null;
+        if(type==1) {
+            companyPhaseVOList=companyMapper.getOnlineCompanyPhaseCount(companyIds, startTime, endTime);
+        }else{
+            companyPhaseVOList=companyMapper.getOfflineCompanyPhaseCount(companyIds, startTime, endTime);
+        }
+        Map<Long,List<CompanyPhaseVO>> companyPhaseVOMap=companyPhaseVOList.stream().collect(Collectors.groupingBy(CompanyPhaseVO::getCompanyId, LinkedHashMap::new,Collectors.toList()));
+        List<CompanyPhaseStudentVO> companyPhaseStudentVOList=null;
+        if(type==1) {
+            companyPhaseStudentVOList=companyMapper.getOnlineCompanyPhaseStudentCount(companyIds, startTime, endTime);
+        }else{
+            companyPhaseStudentVOList=companyMapper.getOfflineCompanyPhaseStudentCount(companyIds, startTime, endTime);
+        }
+        Map<Long,List<CompanyPhaseStudentVO>> companyPhaseStudentVOMap=companyPhaseStudentVOList.stream().collect(Collectors.groupingBy(CompanyPhaseStudentVO::getCompanyId,LinkedHashMap::new,Collectors.toList()));
+
+        List<CompanyPaperStudentVO> companyPaperStudentVOList=null;
+        if(type==1) {
+            companyPaperStudentVOList=companyMapper.getOnlineCompanyPaperStudentCount(companyIds, startTime, endTime);
+        }else{
+            companyPaperStudentVOList=companyMapper.getOfflineCompanyPaperStudentCount(companyIds, startTime, endTime);
+        }
+        Map<Long,CompanyPaperStudentVO> companyPaperStudentVOMap=companyPaperStudentVOList.stream().collect(Collectors.toMap(CompanyPaperStudentVO::getCompanyId,a ->a));
+        List<CompanyStatisticVO> companyStatisticVOList=companyList.stream().map(item -> {
+            CompanyStatisticVO companyStatisticVO=new CompanyStatisticVO();
+            companyStatisticVO.setCompanyId(item.getId());
+            companyStatisticVO.setCompanyName(item.getName());
+            List<CompanyPhaseVO> companyPhaseVOs=companyPhaseVOMap.get(item.getId());
+            if(companyPhaseVOs!=null&&companyPhaseVOs.size()>0){
+                companyPhaseVOs.forEach(cp -> {
+                    if(cp.getLevel().equals(PhaseLevelEnum.COMPANY)){
+                        companyStatisticVO.setLevel1PhaseCount(cp.getPhaseCount());
+                    }else if(cp.getLevel().equals(PhaseLevelEnum.DEPART)){
+                        companyStatisticVO.setLevel2PhaseCount(cp.getPhaseCount());
+                    }else if(cp.getLevel().equals(PhaseLevelEnum.WORkSHOP)) {
+                        companyStatisticVO.setLevel3PhaseCount(cp.getPhaseCount());
+                    }
+                });
+                companyStatisticVO.setPhaseCount(companyPhaseVOs.stream().mapToInt(CompanyPhaseVO::getPhaseCount).sum());
+            }
+            List<CompanyPhaseStudentVO> companyPhaseStudentVOs=companyPhaseStudentVOMap.get(item.getId());
+            if(companyPhaseStudentVOs!=null&&companyPhaseStudentVOs.size()>0){
+                companyPhaseStudentVOs.forEach(cp -> {
+                    if(cp.getLevel().equals(PhaseLevelEnum.COMPANY)){
+                        companyStatisticVO.setLevel1StudentCount(cp.getPhaseStudentCount());
+                    }else if(cp.getLevel().equals(PhaseLevelEnum.DEPART)){
+                        companyStatisticVO.setLevel2StudentCount(cp.getPhaseStudentCount());
+                    }else if(cp.getLevel().equals(PhaseLevelEnum.WORkSHOP)) {
+                        companyStatisticVO.setLevel3StudentCount(cp.getPhaseStudentCount());
+                    }
+                });
+                companyStatisticVO.setPhaseStudentCount(companyPhaseStudentVOs.stream().mapToInt(CompanyPhaseStudentVO::getPhaseStudentCount).sum());
+            }
+            CompanyPaperStudentVO companyPaperStudentVO=companyPaperStudentVOMap.get(item.getId());
+            if(companyPaperStudentVO!=null){
+                companyStatisticVO.setPaperStudentCount(companyPaperStudentVO.getPaperStudentCount());
+                companyStatisticVO.setPassStudentCount(companyPaperStudentVO.getPassStudentCount());
+            }
+            return companyStatisticVO;
+        }).collect(Collectors.toList());
+        return companyStatisticVOList;
+    }
+}
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExStudentServiceImpl.java b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExStudentServiceImpl.java
index 6b6b60e..67ca293 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExStudentServiceImpl.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExStudentServiceImpl.java
@@ -69,15 +69,22 @@
 
     @Override
     public ExStudent selectStudentById(Long studentId) {
-        return baseMapper.selectStudentById(studentId);
+        ExStudent student= baseMapper.selectStudentById(studentId);
+        SysUser currentUser=SecurityUtils.getLoginUser().getUser();
+        if(currentUser.getUserType().equals(UserTypeEnum.SYSTEM_USER.getCode())){
+            return student;
+        }
+        if(!student.getCompanyId().equals(currentUser.getCompanyId())){
+            throw new ApiException("无权限查看其它企业学员");
+        }
+        return student;
+
     }
 
     @Override
     public int insertStudent(ExStudent student) {
         SysUser currentUser= SecurityUtils.getLoginUser().getUser();
-        if(currentUser.getUserType().equals(UserTypeEnum.SYSTEM_USER.getCode())){
-            throw new ApiException("系统管理员不能新增学员");
-        }
+        checkUserAllowed(student);
         if(!checkPhoneUnique(student)){
             throw new ApiException("手机号已存在");
         }
@@ -94,6 +101,7 @@
 
     @Override
     public int updateStudent(ExStudent student) {
+        checkUserAllowed(student);
         if(!checkPhoneUnique(student)){
             throw new ApiException("手机号已存在");
         }
@@ -112,6 +120,7 @@
     @Override
     public int deleteStudentById(Long studentId) {
         ExStudent existStudent=checkUserDataScope(studentId);
+        checkUserAllowed(existStudent);
         int row=baseMapper.deleteByStudentId(studentId);
         if(row<0){
             throw new ApiException("删除学员失败");
@@ -153,6 +162,7 @@
     @Override
     public boolean resetUserPwd(ExStudent student) {
         ExStudent existStudent=getById(student.getId());
+        checkUserAllowed(existStudent);
         ExStudent su=new ExStudent().setId(student.getId()).setPassword(SecurityUtils.encryptPassword(Base64.decodeStr(student.getPassword())));
         su.setUpdateBy(SecurityUtils.getUsername());
         delCacheByPhone(existStudent.getPhone());
@@ -170,4 +180,18 @@
         }
         return student;
     }
+
+    public void checkUserAllowed(ExStudent student) {
+        SysUser currentUser= SecurityUtils.getLoginUser().getUser();
+        if(currentUser.getUserType().equals(UserTypeEnum.SYSTEM_USER.getCode())){
+            throw new ApiException("系统管理员没有权限操作");
+        }
+        if(currentUser.getUserType().equals(UserTypeEnum.STUDENT.getCode())){
+            throw new ApiException("没有权限操作");
+        }
+        if(!currentUser.getCompanyId().equals(student.getCompanyId())){
+            throw new ApiException("没有权限操作其他企业学员");
+        }
+    }
+
 }
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/service/impl/SysCommonServiceImpl.java b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/SysCommonServiceImpl.java
index c09d109..0ccb5d1 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/service/impl/SysCommonServiceImpl.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/SysCommonServiceImpl.java
@@ -1,23 +1,45 @@
 package com.gkhy.exam.system.service.impl;
 
 import cn.hutool.core.date.DateUtil;
+import com.gkhy.exam.common.config.FilePathConfig;
 import com.gkhy.exam.common.exception.ApiException;
+import com.gkhy.exam.common.utils.M3u8Utils;
+import com.gkhy.exam.common.utils.MinioUtils;
 import com.gkhy.exam.system.domain.vo.UploadObjectVO;
 import com.gkhy.exam.system.service.SysCommonService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
 import org.springframework.web.multipart.MultipartFile;
 import sun.misc.BASE64Decoder;
 
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
 import java.io.*;
-import java.util.Date;
-import java.util.UUID;
+import java.time.LocalDateTime;
+import java.util.*;
+import java.util.concurrent.CountDownLatch;
 
 @Service
+@Slf4j
 public class SysCommonServiceImpl implements SysCommonService {
 
     @Value("${image.upload_image}")
     private String uploadPath;
+    @Autowired
+    private M3u8Utils m3u8Utils;
+    @Autowired
+    private MinioUtils minioUtils;
+    @Resource
+    private FilePathConfig filePath;
+
+    @Resource(name = "threadPoolTaskExecutor")
+    private ThreadPoolTaskExecutor poolTaskExecutor;
+
+    String projectUrl = System.getProperty("user.dir").replaceAll("\\\\", "/");
 
     @Override
     public UploadObjectVO uploadFile(MultipartFile file) {
@@ -44,6 +66,93 @@
     }
 
     @Override
+    public String uploadVideo2M3u8(MultipartFile file) throws Exception {
+        String path=m3u8Utils.mediaFileToM3u8(file);
+        return upload2M3u8(path);
+    }
+
+
+    /**
+     * 上传转码后得视频至OSS或minIOn
+     * @param path
+     * @return 路径
+     * @throws Exception
+     */
+    public String upload2M3u8(String path) throws Exception {
+        //存储转码后文件
+        String realPath = path.substring(0, path.lastIndexOf("/"));
+        log.info("视频解析后的 realPath {}", realPath);
+        String name = path.substring(path.lastIndexOf("/") + 1);
+        log.info("解析后视频 name {}", name);
+        File allFile = new File(realPath);
+        File[] files = allFile.listFiles();
+        if (null == files || files.length == 0) {
+            return null;
+        }
+        String patch = DateUtil.format(LocalDateTime.now(), "yyyy/MM/") + name.substring(0, name.lastIndexOf(".")) + "/";
+        List<File> errorFile = new ArrayList<>();
+
+        long start = System.currentTimeMillis();
+//        //替换m3u8文件中的路径
+//        FileUtil.replaceTextContent(path, name.substring(0, name.lastIndexOf(".")),
+//                aliOssProperties.getMyHostUrl() + filePath.getProxy() + patch +
+//                        name.substring(0, name.lastIndexOf(".")));
+        //开始上传
+        CountDownLatch countDownLatch = new CountDownLatch(files.length);
+        Arrays.stream(files).forEach(li -> poolTaskExecutor.execute(() -> {
+            try (FileInputStream fileInputStream = new FileInputStream(li)) {
+                minioUtils.fileUploader(patch + li.getName(), fileInputStream);
+
+                log.info("文件:{} 正在上传", li.getName());
+            } catch (Exception e) {
+                errorFile.add(li);
+                e.printStackTrace();
+            } finally {
+                countDownLatch.countDown();
+            }
+        }));
+        countDownLatch.await();
+        long end = System.currentTimeMillis();
+        log.info("解析文件上传成功,共计:{} 个文件,失败:{},共耗时: {}ms", files.length, errorFile.size(), end - start);
+        //  try {
+        //      minioComponent.mkBucket("m3u8");
+        //  } catch (Exception e) {
+        //      log.error("创建Bucket失败!");
+        //  }
+
+        //异步移除所有文件
+        poolTaskExecutor.execute(() -> {
+            deleteFile(projectUrl+filePath.getTempPath());
+        });
+        if (CollectionUtils.isEmpty(errorFile)) {
+            return  filePath.getProxy() + patch + name;
+        }
+        return "";
+    }
+
+    public static void deleteFile(String path){
+        File dest = new File(path);
+        if (dest.isFile() && dest.exists()) {
+            dest.delete();
+        }
+    }
+
+    @Override
+    public boolean uploadSlice(HttpServletRequest request, String guid, Integer chunk, MultipartFile file) {
+        return false;
+    }
+
+    @Override
+    public String uploadVideoMerge(String guid, String fileName) {
+        return null;
+    }
+
+    @Override
+    public String uploadMerge(String guid, String fileName) {
+        return null;
+    }
+
+    @Override
     public UploadObjectVO doUpload(MultipartFile file){
         String originName=file.getOriginalFilename();
         String filename=originName;
diff --git a/exam-system/src/main/resources/mapper/system/ExExamPaperMapper.xml b/exam-system/src/main/resources/mapper/system/ExExamPaperMapper.xml
index 0725ae9..0daa0aa 100644
--- a/exam-system/src/main/resources/mapper/system/ExExamPaperMapper.xml
+++ b/exam-system/src/main/resources/mapper/system/ExExamPaperMapper.xml
@@ -50,6 +50,7 @@
         update ex_exam_paper set del_flag=1 where id=#{paperId}
     </update>
 
+
     <select id="selectExamPaperList" resultMap="ExamPaperResult">
         <include refid="selectExamPaperVo"/>
         <where>
diff --git a/exam-system/src/main/resources/mapper/system/ExExamRecordMapper.xml b/exam-system/src/main/resources/mapper/system/ExExamRecordMapper.xml
new file mode 100644
index 0000000..5f2e6c0
--- /dev/null
+++ b/exam-system/src/main/resources/mapper/system/ExExamRecordMapper.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.gkhy.exam.system.mapper.ExExamRecordMapper">
+    <resultMap type="com.gkhy.exam.system.domain.ExExamRecord" id="ExamRecordResult">
+        <result property="id"       column="id"       />
+        <result property="companyId"    column="company_id"    />
+        <result property="studentId"     column="student_id"     />
+        <result property="planName"         column="plan_name"          />
+        <result property="courseName"         column="course_name"          />
+        <result property="level"         column="level"          />
+        <result property="period"         column="period"          />
+        <result property="actualPeriod"         column="actual_period"          />
+        <result property="score"         column="score"          />
+        <result property="companyId"         column="company_id"          />
+        <result property="passed"         column="passed"          />
+        <result property="createBy"       column="create_by"       />
+        <result property="createTime"     column="create_time"     />
+        <result property="updateBy"       column="update_by"       />
+        <result property="updateTime"     column="update_time"     />
+        <result property="remark"         column="remark"          />
+        <result property="companyName"         column="company_name"          />
+    </resultMap>
+
+    <sql id="selectExamRecordVo">
+        select a.id, a.company_id, a.student_id, a.plan_name, a.course_name,a.level,a.period,a.actual_period,a.score,
+               a.company_id,a.passed, a.create_by, a.create_time, a.update_by, a.update_time, a.remark,b.name as company_name
+        from ex_exam_record a
+        left join sys_company b on b.id=a.company_id
+    </sql>
+
+    <select id="selectExamRecordList" resultMap="ExamRecordResult">
+        <include refid="selectExamRecordVo"/>
+        <where>
+            <if test="planName != null and planName != ''">
+                AND a.plan_name like concat('%', #{planName}, '%')
+            </if>
+            <if test="companyId != null ">
+                AND a.company_id =#{companyId}
+            </if>
+        </where>
+        order by a.id desc
+    </select>
+
+    <select id="selectExamRecordById" resultMap="ExamRecordResult">
+        <include refid="selectExamRecordVo"/>
+        where a.id=#{recordId}
+    </select>
+</mapper>
diff --git a/exam-system/src/main/resources/mapper/system/ExPaperStudentMapper.xml b/exam-system/src/main/resources/mapper/system/ExPaperStudentMapper.xml
index a6b49c8..d87acb8 100644
--- a/exam-system/src/main/resources/mapper/system/ExPaperStudentMapper.xml
+++ b/exam-system/src/main/resources/mapper/system/ExPaperStudentMapper.xml
@@ -57,6 +57,7 @@
         left join ex_student b on a.student_id=b.id
         left join ex_exam_paper c on c.id=a.paper_id
         <where>
+            and c.del_flag=0
             <if test="paperId!=null'">
                 and a.paper_id=#{paperId}
             </if>
diff --git a/exam-system/src/main/resources/mapper/system/SysCompanyMapper.xml b/exam-system/src/main/resources/mapper/system/SysCompanyMapper.xml
index 75babe2..bf14ee4 100644
--- a/exam-system/src/main/resources/mapper/system/SysCompanyMapper.xml
+++ b/exam-system/src/main/resources/mapper/system/SysCompanyMapper.xml
@@ -34,8 +34,11 @@
             <if test="creditCode != null and creditCode != ''">
                 AND credit_code like concat('%', #{creditCode}, '%')
             </if>
+            <if test="id!=null">
+                AND id=#{id}
+            </if>
         </where>
-        order by create_time desc
+        order by id desc
     </select>
 
     <select id="selectCompanyById" resultMap="SysCompanyResult">
@@ -52,4 +55,101 @@
     <select id="checkNameUnique" resultMap="SysCompanyResult">
         select id,name from sys_company where name=#{name} and del_flag=0 limit 1
     </select>
+
+    <select id="getOnlineCompanyPhaseCount" resultType="com.gkhy.exam.system.domain.vo.CompanyPhaseVO">
+        select count(a.id) as phase_count,a.level,a.company_id from ex_course_phase a
+        inner join sys_company b on b.id=a.company_id
+        where a.del_flag=0 and b.del_flag=0 and a.company_id in
+        <foreach collection="companyIds" item="companyId" open="(" separator="," close=")">
+            #{companyId}
+        </foreach>
+        <if test="startTime!=null and startTime!=''">
+            and a.create_time &gt;= #{startTime}
+        </if>
+        <if test="endTime!=null and endTime!=''">
+            and a.create_time &lt;= #{endTime}
+        </if>
+        group by a.company_id,a.level
+    </select>
+
+    <select id="getOnlineCompanyPhaseStudentCount" resultType="com.gkhy.exam.system.domain.vo.CompanyPhaseStudentVO">
+        select count(1) as phase_student_count,b.company_id,b.level from ex_phase_student a
+        inner join ex_course_phase b on b.id=a.phase_id
+        where b.del_flag=0 and b.company_id in
+        <foreach collection="companyIds" item="companyId" open="(" separator="," close=")">
+            #{companyId}
+        </foreach>
+        <if test="startTime!=null and startTime!=''">
+            and b.create_time &gt;= #{startTime}
+        </if>
+        <if test="endTime!=null and endTime!=''">
+            and b.create_time &lt;= #{endTime}
+        </if>
+        group by b.company_id,b.level
+    </select>
+
+    <select id="getOnlineCompanyPaperStudentCount" resultType="com.gkhy.exam.system.domain.vo.CompanyPaperStudentVO">
+        select count(a.id) as paper_student_count,sum(a.passed) as pass_student_count,b.company_id from ex_paper_student a
+        inner join ex_exam_paper b on b.id=a.paper_id
+        where b.del_flag=0 and b.company_id in
+        <foreach collection="companyIds" item="companyId" open="(" separator="," close=")">
+            #{companyId}
+        </foreach>
+        <if test="startTime!=null and startTime!=''">
+            and b.create_time &gt;= #{startTime}
+        </if>
+        <if test="endTime!=null and endTime!=''">
+            and b.create_time &lt;= #{endTime}
+        </if>
+        group by b.company_id
+    </select>
+
+    <select id="getOfflineCompanyPhaseCount" resultType="com.gkhy.exam.system.domain.vo.CompanyPhaseVO">
+        select count(f.plan_name)as phase_count,f.company_id,f.level  from (
+        select a.plan_name,a.company_id,a.level from ex_exam_record a
+        inner join sys_company b on b.id=a.company_id
+        where b.del_flag=0 and a.company_id in
+        <foreach collection="companyIds" item="companyId" open="(" separator="," close=")">
+            #{companyId}
+        </foreach>
+        <if test="startTime!=null and startTime!=''">
+            and a.create_time &gt;= #{startTime}
+        </if>
+        <if test="endTime!=null and endTime!=''">
+            and a.create_time &lt;= #{endTime}
+        </if>
+        group by a.company_id,a.level,a.plan_name
+        ) as f group by f.company_id,f.level
+    </select>
+    <select id="getOfflineCompanyPhaseStudentCount" resultType="com.gkhy.exam.system.domain.vo.CompanyPhaseStudentVO">
+        select count(1) as phase_student_count,b.company_id,b.level from ex_exam_record a
+        inner join sys_company b on b.id=a.company_id
+        where b.del_flag=0 and a.company_id in
+        <foreach collection="companyIds" item="companyId" open="(" separator="," close=")">
+            #{companyId}
+        </foreach>
+        <if test="startTime!=null and startTime!=''">
+            and a.create_time &gt;= #{startTime}
+        </if>
+        <if test="endTime!=null and endTime!=''">
+            and a.create_time &lt;= #{endTime}
+        </if>
+        group by a.company_id,a.level
+    </select>
+
+    <select id="getOfflineCompanyPaperStudentCount" resultType="com.gkhy.exam.system.domain.vo.CompanyPaperStudentVO">
+        select count(a.id) as paper_student_count,sum(a.passed) as pass_student_count,a.company_id from ex_exam_record a
+        inner join sys_company b on b.id=a.paper_id
+        where b.del_flag=0 and score is not null and a.company_id in
+        <foreach collection="companyIds" item="companyId" open="(" separator="," close=")">
+            #{companyId}
+        </foreach>
+        <if test="startTime!=null and startTime!=''">
+            and a.create_time &gt;= #{startTime}
+        </if>
+        <if test="endTime!=null and endTime!=''">
+            and a.create_time &lt;= #{endTime}
+        </if>
+        group by a.company_id
+    </select>
 </mapper>
diff --git a/exam-system/src/test/java/com/gkhy/exam/system/MybatisPlusGenerator.java b/exam-system/src/test/java/com/gkhy/exam/system/MybatisPlusGenerator.java
index 9174c19..dd1fc3c 100644
--- a/exam-system/src/test/java/com/gkhy/exam/system/MybatisPlusGenerator.java
+++ b/exam-system/src/test/java/com/gkhy/exam/system/MybatisPlusGenerator.java
@@ -16,7 +16,7 @@
         String model="/exam-system";
         // 数据库配置
         DataSourceConfig.Builder dataSourceConfigBuilder = new DataSourceConfig
-                .Builder("jdbc:mysql://192.168.0.23:7006/train_exam" +
+                .Builder("jdbc:mysql://192.168.2.16:7006/train_exam" +
                 "?useSSL=false&allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true"
                 , "root", "2farwL3yPXfbH2AP");
         FastAutoGenerator.create(dataSourceConfigBuilder)
diff --git a/pom.xml b/pom.xml
index dbf324c..6a9fdca 100644
--- a/pom.xml
+++ b/pom.xml
@@ -40,6 +40,7 @@
         <minio.version>8.4.5</minio.version>
         <kaptcha.version>2.3.3</kaptcha.version>
         <bitwalker.version>1.21</bitwalker.version>
+        <ffmpeg.version>0.7.0</ffmpeg.version>
     </properties>
     <dependencyManagement>
         <dependencies>
@@ -69,7 +70,6 @@
                 <groupId>com.github.pagehelper</groupId>
                 <artifactId>pagehelper-spring-boot-starter</artifactId>
                 <version>${pagehelper.version}</version>
-
             </dependency>
             <!--Hutool Java工具包-->
             <dependency>
@@ -151,6 +151,12 @@
                 <version>${bitwalker.version}</version>
             </dependency>
 
+            <dependency>
+                <groupId>net.bramp.ffmpeg</groupId>
+                <artifactId>ffmpeg</artifactId>
+                <version>${ffmpeg.version}</version>
+            </dependency>
+
         </dependencies>
     </dependencyManagement>
 

--
Gitblit v1.9.2