From f0f00e9ba8a755e4317e029d73b69a92ad9f9df1 Mon Sep 17 00:00:00 2001
From: kongzy <kongzy>
Date: 星期六, 14 九月 2024 17:02:41 +0800
Subject: [PATCH] update

---
 exam-admin/src/main/resources/db/migration/V20240531003_carousel.sql                                   |    1 
 exam-system/src/main/java/com/gkhy/exam/system/mapper/ExCourseMapper.java                              |   10 
 exam-common/src/main/java/com/gkhy/exam/common/annotation/DataDesensitizationType.java                 |   19 
 exam-framework/src/main/java/com/gkhy/exam/framework/aspectj/LogAspect.java                            |  289 +--
 exam-common/src/main/java/com/gkhy/exam/common/excel/StudentExcelDataListener.java                     |   17 
 exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExResourceController.java                  |    2 
 exam-system/src/main/resources/mapper/system/ExCourseMapper.xml                                        |   23 
 exam-admin/src/main/resources/db/migration/V20240531005_course.sql                                     |    5 
 exam-framework/src/main/java/com/gkhy/exam/framework/aspectj/DataDesensitizationAspect.java            |   44 
 exam-framework/src/main/java/com/gkhy/exam/framework/job/UserStudyJob.java                             |   38 
 exam-admin/src/main/resources/db/migration/V20231018009_dict_type.sql                                  |    1 
 exam-system/src/main/resources/mapper/system/ExCourseChapterMapper.xml                                 |    7 
 exam-admin/src/main/resources/db/migration/V20240614001_question_bank.sql                              |    3 
 exam-admin/src/main/java/com/gkhy/exam/admin/controller/app/AppPaperStudentController.java             |    7 
 exam-admin/src/main/resources/application-prod.yml                                                     |   86 +
 exam-framework/src/main/java/com/gkhy/exam/framework/web/service/SysLoginService.java                  |   20 
 exam-admin/src/main/java/com/gkhy/exam/admin/controller/system/SysConfigController.java                |    2 
 exam-system/src/main/resources/mapper/system/ExStudentAnswerMapper.xml                                 |    2 
 exam-admin/src/main/java/com/gkhy/exam/admin/controller/app/AppResourceController.java                 |    2 
 exam-system/src/main/resources/mapper/system/ExQuestionMapper.xml                                      |   66 
 exam-admin/src/main/resources/db/migration/V20240506001_ope_log.sql                                    |    1 
 exam-framework/src/main/java/com/gkhy/exam/framework/web/service/TokenService.java                     |   33 
 exam-system/src/main/java/com/gkhy/exam/system/mapper/ExExamPaperMapper.java                           |    2 
 exam-admin/src/main/resources/db/migration/V20240731001_change_question.sql                            |    2 
 exam-admin/src/main/java/com/gkhy/exam/admin/controller/system/SysDictTypeController.java              |    2 
 exam-system/src/main/java/com/gkhy/exam/system/mapper/SysUserMapper.java                               |    7 
 exam-system/src/main/java/com/gkhy/exam/system/mapper/ExCourseChapterPeriodMapper.java                 |    7 
 exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExPaperStudentController.java              |   32 
 exam-system/src/main/java/com/gkhy/exam/system/service/impl/SysCompanyServiceImpl.java                 |    1 
 pom.xml                                                                                                |   19 
 exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExExamRecordServiceImpl.java               |    7 
 exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExExerciseAnswerServiceImpl.java           |    7 
 exam-admin/src/main/resources/logback-spring.xml                                                       |  102 +
 exam-common/src/main/java/com/gkhy/exam/common/utils/SecurityUtils.java                                |   16 
 exam-system/src/main/java/com/gkhy/exam/system/domain/vo/CompanyPaperStudentVO.java                    |    4 
 exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExExamPaperController.java                 |    8 
 exam-system/src/main/java/com/gkhy/exam/system/domain/ExPhaseStudent.java                              |   13 
 exam-common/src/main/java/com/gkhy/exam/common/enums/StudentAnswerPassEnum.java                        |   29 
 exam-common/src/main/java/com/gkhy/exam/common/annotation/DataDesensitization.java                     |   13 
 exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExStudentAnswerServiceImpl.java            |   24 
 exam-system/src/main/java/com/gkhy/exam/system/domain/vo/PaperStudentInfoVO.java                       |   34 
 exam-admin/src/test/java/com/gkhy/exam/admin/QuestionTest.java                                         |  198 ++
 exam-system/src/main/java/com/gkhy/exam/system/domain/ExStudent.java                                   |   32 
 exam-system/src/main/java/com/gkhy/exam/system/domain/vo/TrainRecordVO.java                            |   32 
 exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExPaperStudentServiceImpl.java             |  201 +
 exam-admin/src/main/java/com/gkhy/exam/admin/controller/app/AppCourseController.java                   |    4 
 exam-admin/src/main/java/com/gkhy/exam/admin/controller/app/AppExerciseAnswerController.java           |    4 
 exam-admin/src/main/java/com/gkhy/exam/admin/controller/system/SysUserController.java                  |    4 
 exam-system/src/main/java/com/gkhy/exam/system/service/impl/SysCarouselServiceImpl.java                |    6 
 exam-admin/src/main/resources/db/migration/V20231018010_dict_data.sql                                  |    1 
 exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExQuestionController.java                  |    4 
 exam-admin/src/main/java/com/gkhy/exam/admin/controller/app/AppQuestionController.java                 |   15 
 exam-system/src/main/java/com/gkhy/exam/system/domain/SysCategory.java                                 |    4 
 exam-system/src/main/java/com/gkhy/exam/system/mapper/ExResourceMapper.java                            |    7 
 exam-system/src/main/resources/mapper/system/ExCourseChapterPeriodMapper.xml                           |    4 
 exam-admin/src/main/java/com/gkhy/exam/admin/controller/app/AppQuestionBankController.java             |    2 
 exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExCourseServiceImpl.java                   |   29 
 exam-system/src/main/resources/mapper/system/ExResourceMapper.xml                                      |    5 
 exam-system/src/main/resources/mapper/system/SysCompanyMapper.xml                                      |    3 
 exam-admin/src/main/resources/db/migration/V20240604001_exam_record.sql                                |    3 
 exam-system/src/main/resources/mapper/system/ExExamPaperMapper.xml                                     |   45 
 exam-system/src/main/resources/mapper/system/SysCarouselMapper.xml                                     |    2 
 exam-admin/src/main/resources/db/migration/V20240828001_change_question.sql                            |    2 
 exam-system/src/main/resources/mapper/system/ExStudentMapper.xml                                       |   22 
 exam-admin/src/main/resources/db/migration/V20240603003_question.sql                                   |    1 
 exam-system/src/main/java/com/gkhy/exam/system/domain/vo/CompanyPhaseStudentVO.java                    |    4 
 exam-admin/src/main/resources/db/migration/V20240603005_paper_question.sql                             |    1 
 exam-admin/src/main/java/com/gkhy/exam/admin/controller/app/AppStudentStudyController.java             |    5 
 exam-system/src/main/java/com/gkhy/exam/system/domain/ExCompanyPeriod.java                             |    8 
 exam-system/src/main/java/com/gkhy/exam/system/domain/ExStudentAnswer.java                             |    6 
 error.xlsx                                                                                             |    0 
 exam-admin/src/main/java/com/gkhy/exam/admin/controller/system/SysCompanyController.java               |    2 
 exam-framework/src/main/java/com/gkhy/exam/framework/event/PaperStudentListener.java                   |   82 
 exam-common/src/main/java/com/gkhy/exam/common/filter/XssFilter.java                                   |   70 
 exam-system/src/main/java/com/gkhy/exam/system/service/impl/SysCategoryServiceImpl.java                |   13 
 exam-system/src/main/java/com/gkhy/exam/system/domain/vo/ExPaperStudentVO.java                         |   60 
 exam-system/src/main/resources/mapper/system/ExPaperStudentMapper.xml                                  |   87 
 exam-system/src/main/java/com/gkhy/exam/system/domain/vo/CompanyPhaseVO.java                           |    6 
 exam-admin/src/main/resources/application.yml                                                          |   16 
 exam-admin/src/main/java/com/gkhy/exam/admin/controller/system/SysLoginController.java                 |    4 
 exam-admin/src/main/java/com/gkhy/exam/admin/controller/system/SysCarouselController.java              |    3 
 exam-system/src/main/java/com/gkhy/exam/system/mapper/SysCategoryMapper.java                           |   12 
 exam-admin/src/main/java/com/gkhy/exam/admin/controller/app/AppStudentController.java                  |   43 
 exam-common/pom.xml                                                                                    |   13 
 exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExCompanyPeriodController.java             |    2 
 exam-admin/pom.xml                                                                                     |   31 
 exam-system/src/main/java/com/gkhy/exam/system/domain/ExCoursePhase.java                               |   18 
 exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExCourseChapterPeriodController.java       |    2 
 exam-admin/src/main/resources/db/migration/V20240510001_loginfor.sql                                   |    1 
 exam-admin/src/main/resources/db/migration/V20240531008_resource.sql                                   |    5 
 exam-admin/src/main/resources/db/migration/V20240603001_exam_paper.sql                                 |    4 
 exam-admin/src/main/java/com/gkhy/exam/admin/controller/system/SysProfileController.java               |    2 
 exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExCoursePhaseController.java               |    4 
 exam-system/src/main/java/com/gkhy/exam/system/service/ExPaperStudentService.java                      |   19 
 exam-system/src/main/java/com/gkhy/exam/system/domain/vo/StudentStudyPeriodVO.java                     |    8 
 exam-common/src/main/java/com/gkhy/exam/common/constant/Constant.java                                  |   10 
 exam-common/src/main/java/com/gkhy/exam/common/enums/QuestionTypeEnum.java                             |    3 
 exam-system/src/main/java/com/gkhy/exam/system/mapper/ExPaperQuestionMapper.java                       |    5 
 exam-admin/src/main/java/com/gkhy/exam/admin/controller/app/AppLoginController.java                    |    4 
 exam-system/src/main/resources/mapper/system/ExExamRecordMapper.xml                                    |   12 
 exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExStatisticController.java                 |    5 
 exam-framework/src/main/java/com/gkhy/exam/framework/event/PaperStudentEvent.java                      |   16 
 exam-system/src/main/resources/mapper/system/SysCategoryMapper.xml                                     |   18 
 exam-admin/src/main/resources/application-dev.yml                                                      |   50 
 exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExCourseChapterServiceImpl.java            |   28 
 exam-admin/src/main/resources/db/migration/V20231110001_config.sql                                     |    1 
 exam-common/src/main/java/com/gkhy/exam/common/utils/html/EscapeUtil.java                              |  167 +
 exam-admin/src/main/resources/db/migration/V20240801002_change_exam_paper.sql                          |   14 
 exam-admin/src/main/java/com/gkhy/exam/admin/controller/system/SysCommonController.java                |    9 
 exam-system/src/main/java/com/gkhy/exam/system/domain/SysCompany.java                                  |   15 
 exam-admin/src/main/resources/db/migration/V20240801001_change_paper_student.sql                       |    2 
 exam-common/src/main/java/com/gkhy/exam/common/excel/StudentExcelData.java                             |   51 
 exam-system/src/main/java/com/gkhy/exam/system/domain/vo/StudentStudyVO.java                           |    4 
 exam-admin/src/main/java/com/gkhy/exam/admin/controller/monitor/SysOperLogController.java              |    2 
 exam-admin/src/main/resources/db/migration/V20240802001_change_student_answer.sql                      |    5 
 exam-admin/src/main/resources/db/migration/V20231016001_add_user.sql                                   |    5 
 exam-system/src/main/java/com/gkhy/exam/system/domain/ExQuestionBank.java                              |   22 
 exam-admin/src/test/java/com/gkhy/exam/admin/PasswordTest.java                                         |   12 
 exam-admin/src/main/resources/db/migration/V20240531006_course_chapter.sql                             |    1 
 exam-framework/src/main/java/com/gkhy/exam/framework/config/FastjsonConfig.java                        |   68 
 exam-common/src/main/java/com/gkhy/exam/common/utils/html/HTMLFilter.java                              |  566 ++++++
 exam-system/src/main/java/com/gkhy/exam/system/domain/ExPaperStudent.java                              |   36 
 exam-admin/src/main/resources/db/migration/V20240801003_change_student_answer.sql                      |    3 
 exam-system/src/main/java/com/gkhy/exam/system/domain/vo/UploadObjectVO.java                           |    4 
 exam-admin/src/main/java/com/gkhy/exam/admin/controller/app/AppPhaseStudentController.java             |    2 
 exam-admin/src/main/java/com/gkhy/exam/admin/controller/app/AppStudentAnswerController.java            |    2 
 exam-system/src/main/java/com/gkhy/exam/system/service/ExQuestionService.java                          |   10 
 exam-admin/src/main/java/com/gkhy/exam/admin/controller/system/CaptchaController.java                  |    2 
 exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExStatisticServiceImpl.java                |   31 
 exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExStudentController.java                   |   28 
 exam-admin/src/main/resources/db/migration/V20240531001_student.sql                                    |    1 
 exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExCourseController.java                    |    2 
 exam-system/src/main/java/com/gkhy/exam/system/domain/ExExamRecord.java                                |   32 
 exam-admin/src/main/resources/db/migration/V20240531002_company.sql                                    |    6 
 exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExCourseChapterController.java             |    2 
 exam-admin/src/main/resources/db/migration/V20240619001_exercise_answer.sql                            |    3 
 exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExCourseChapterPeriodServiceImpl.java      |    7 
 exam-system/src/main/java/com/gkhy/exam/system/domain/ExExamPaper.java                                 |   99 
 exam-admin/src/main/resources/db/migration/V20240428001_notice.sql                                     |    1 
 exam-framework/src/main/java/com/gkhy/exam/framework/config/FilterConfig.java                          |   64 
 exam-admin/src/test/java/com/gkhy/exam/admin/JobTest.java                                              |   27 
 exam-admin/src/main/java/com/gkhy/exam/admin/controller/system/SysNoticeController.java                |    2 
 exam-common/src/main/java/com/gkhy/exam/common/utils/DesenseUtil.java                                  |   78 
 exam-common/src/main/java/com/gkhy/exam/common/config/FFmpegConfig.java                                |    7 
 exam-admin/src/main/java/com/gkhy/exam/admin/controller/app/AppCarouselController.java                 |    3 
 exam-admin/src/test/java/com/gkhy/exam/admin/ExcelTest.java                                            |   24 
 exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExStudentStudyServiceImpl.java             |   20 
 exam-common/src/main/java/com/gkhy/exam/common/utils/M3u8Utils.java                                    |    7 
 exam-system/src/main/java/com/gkhy/exam/system/service/SysCommonService.java                           |    3 
 exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExQuestionBankServiceImpl.java             |    3 
 exam-admin/src/main/resources/db/migration/V20240531012_company_period.sql                             |    5 
 exam-framework/src/main/java/com/gkhy/exam/framework/job/PaperStudentJob.java                          |   70 
 exam-system/src/main/java/com/gkhy/exam/system/service/SysUserService.java                             |    1 
 exam-system/src/main/java/com/gkhy/exam/system/domain/ExCourse.java                                    |   18 
 exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExStudentServiceImpl.java                  |  163 +
 exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExQuestionBankController.java              |    2 
 exam-common/src/main/java/com/gkhy/exam/common/utils/ServletUtils.java                                 |    1 
 exam-admin/src/main/resources/db/migration/V20240531004_category.sql                                   |    2 
 exam-framework/src/main/java/com/gkhy/exam/framework/exception/GlobalExceptionHandler.java             |    2 
 exam-admin/src/main/java/com/gkhy/exam/admin/controller/monitor/SysLogininforController.java           |    2 
 exam-common/src/main/java/com/gkhy/exam/common/enums/SensitiveTypeEnum.java                            |   10 
 exam-system/src/main/java/com/gkhy/exam/system/domain/vo/CompanyStatisticVO.java                       |    4 
 exam-system/src/main/resources/mapper/system/ExQuestionBankMapper.xml                                  |   69 
 exam-admin/src/main/resources/application-guotai.yml                                                   |   86 +
 exam-system/src/main/resources/mapper/system/ExStudentStudyMapper.xml                                  |    5 
 exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExStudentStudyController.java              |    2 
 exam-common/src/main/java/com/gkhy/exam/common/enums/PaperStudentStateEnum.java                        |   29 
 exam-system/src/main/java/com/gkhy/exam/system/mapper/ExPaperStudentMapper.java                        |   25 
 exam-system/src/main/java/com/gkhy/exam/system/domain/ExStudentStudy.java                              |    3 
 exam-common/src/main/java/com/gkhy/exam/common/filter/XssHttpServletRequestWrapper.java                |  111 +
 exam-system/src/main/java/com/gkhy/exam/system/mapper/ExStudentMapper.java                             |    3 
 exam-system/src/main/resources/mapper/system/ExPhaseStudentMapper.xml                                  |   27 
 exam-system/src/main/java/com/gkhy/exam/system/mapper/ExQuestionBankMapper.java                        |   22 
 exam-system/src/main/java/com/gkhy/exam/system/mapper/ExPhaseStudentMapper.java                        |    7 
 exam-framework/src/main/java/com/gkhy/exam/framework/security/handle/AuthenticationEntryPointImpl.java |    2 
 exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExCoursePhaseServiceImpl.java              |   21 
 exam-system/src/main/resources/mapper/system/ExCoursePhaseMapper.xml                                   |   29 
 exam-system/src/main/java/com/gkhy/exam/system/service/impl/SysCommonServiceImpl.java                  |  106 +
 exam-admin/src/main/resources/db/migration/V20240531011_phase_student.sql                              |    1 
 exam-system/src/main/java/com/gkhy/exam/system/service/impl/SysUserServiceImpl.java                    |   30 
 exam-system/src/main/java/com/gkhy/exam/system/service/ExStudentService.java                           |   21 
 exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExPhaseStudentServiceImpl.java             |   31 
 exam-system/src/main/java/com/gkhy/exam/system/domain/ExQuestion.java                                  |   13 
 exam-admin/src/main/java/com/gkhy/exam/admin/controller/system/SysCategoryController.java              |    2 
 exam-admin/src/main/resources/db/migration/V20240531010_student_study.sql                              |    2 
 exam-admin/src/main/java/com/gkhy/exam/admin/controller/system/SysDictDataController.java              |    2 
 exam-system/src/main/resources/mapper/system/ExExerciseAnswerMapper.xml                                |    2 
 exam-common/src/main/java/com/gkhy/exam/common/domain/TableSupport.java                                |    6 
 exam-system/src/main/resources/mapper/system/SysUserMapper.xml                                         |   27 
 exam-system/src/main/java/com/gkhy/exam/system/mapper/ExQuestionMapper.java                            |   39 
 exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExResourceServiceImpl.java                 |   26 
 exam-system/src/main/java/com/gkhy/exam/system/domain/ExExerciseAnswer.java                            |    4 
 exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExQuestionServiceImpl.java                 |  116 
 exam-admin/src/main/resources/db/migration/V20240531009_course_phase.sql                               |    1 
 exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExExamRecordController.java                |    2 
 exam-common/src/main/java/com/gkhy/exam/common/domain/entity/SysUser.java                              |    7 
 exam-admin/src/main/resources/db/migration/V20240603004_student_answer.sql                             |    1 
 exam-framework/src/main/java/com/gkhy/exam/framework/security/SecurityConfig.java                      |    4 
 exam-system/src/main/resources/mapper/system/ExPaperQuestionMapper.xml                                 |    7 
 exam-system/src/main/java/com/gkhy/exam/system/domain/vo/BatchPaperStudentVO.java                      |   29 
 exam-admin/src/main/resources/db/migration/V20240603002_paper_student.sql                              |    1 
 exam-admin/src/main/resources/db/migration/V20240531007_course_chapter_period.sql                      |    1 
 exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExExamPaperServiceImpl.java                |  107 +
 exam-framework/src/main/java/com/gkhy/exam/framework/config/ApplicationConfig.java                     |    9 
 exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExPhaseStudentController.java              |    6 
 205 files changed, 4,269 insertions(+), 827 deletions(-)

diff --git a/error.xlsx b/error.xlsx
new file mode 100644
index 0000000..a6329b4
--- /dev/null
+++ b/error.xlsx
Binary files differ
diff --git a/exam-admin/pom.xml b/exam-admin/pom.xml
index 17919e0..4e135c8 100644
--- a/exam-admin/pom.xml
+++ b/exam-admin/pom.xml
@@ -29,4 +29,35 @@
         </dependency>
     </dependencies>
 
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>2.5.15</version>
+                <configuration>
+                    <fork>true</fork> <!-- 如果没有该配置,devtools不会生效 -->
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-war-plugin</artifactId>
+                <version>3.1.0</version>
+                <configuration>
+                    <failOnMissingWebXml>false</failOnMissingWebXml>
+                    <warName>${project.artifactId}</warName>
+                </configuration>
+            </plugin>
+        </plugins>
+        <finalName>${project.artifactId}</finalName>
+    </build>
+
+
 </project>
\ No newline at end of file
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppCarouselController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/app/AppCarouselController.java
similarity index 92%
rename from exam-admin/src/main/java/com/gkhy/exam/admin/app/AppCarouselController.java
rename to exam-admin/src/main/java/com/gkhy/exam/admin/controller/app/AppCarouselController.java
index 415437b..1f5e265 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppCarouselController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/app/AppCarouselController.java
@@ -1,4 +1,4 @@
-package com.gkhy.exam.admin.app;
+package com.gkhy.exam.admin.controller.app;
 
 
 import com.gkhy.exam.common.api.CommonResult;
@@ -28,6 +28,7 @@
     @Autowired
     private SysCarouselService carouselService;
 
+  //  @PreAuthorize("hasAnyAuthority('train:exam:student')")
     @ApiOperation(value = "轮播列表(分页)")
     @ApiImplicitParams({
             @ApiImplicitParam(paramType = "query", name = "pageNum", dataType = "int", required = false, value = "当前页,默认1"),
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppCourseController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/app/AppCourseController.java
similarity index 86%
rename from exam-admin/src/main/java/com/gkhy/exam/admin/app/AppCourseController.java
rename to exam-admin/src/main/java/com/gkhy/exam/admin/controller/app/AppCourseController.java
index b02ee31..aa1f8db 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppCourseController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/app/AppCourseController.java
@@ -1,4 +1,4 @@
-package com.gkhy.exam.admin.app;
+package com.gkhy.exam.admin.controller.app;
 
 
 import com.gkhy.exam.common.api.CommonResult;
@@ -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.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -26,6 +27,7 @@
     @Autowired
     private ExCourseService courseService;
 
+    @PreAuthorize("hasAnyAuthority('train:exam:student')")
     @ApiOperation(value = "根据id获取课程信息")
     @GetMapping(value = { "/{courseId}" })
     public CommonResult getCompanyInfo(@PathVariable(value = "courseId", required = true) Long courseId)
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/controller/app/AppExerciseAnswerController.java
similarity index 93%
rename from exam-admin/src/main/java/com/gkhy/exam/admin/app/AppExerciseAnswerController.java
rename to exam-admin/src/main/java/com/gkhy/exam/admin/controller/app/AppExerciseAnswerController.java
index fc35d52..40de45b 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppExerciseAnswerController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/app/AppExerciseAnswerController.java
@@ -1,4 +1,4 @@
-package com.gkhy.exam.admin.app;
+package com.gkhy.exam.admin.controller.app;
 
 
 import com.gkhy.exam.common.api.CommonResult;
@@ -22,7 +22,7 @@
  * @author kzy
  * @since 2024-06-20 09:42:25
  */
-@Api(tags = "学员刷题前端控制器")
+@Api(tags = "APP学员刷题前端控制器")
 @RestController
 @RequestMapping("/app/exercise-answer")
 public class AppExerciseAnswerController {
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppLoginController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/app/AppLoginController.java
similarity index 93%
rename from exam-admin/src/main/java/com/gkhy/exam/admin/app/AppLoginController.java
rename to exam-admin/src/main/java/com/gkhy/exam/admin/controller/app/AppLoginController.java
index a66ef04..9e632fa 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppLoginController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/app/AppLoginController.java
@@ -1,4 +1,4 @@
-package com.gkhy.exam.admin.app;
+package com.gkhy.exam.admin.controller.app;
 
 
 import com.gkhy.exam.common.api.CommonResult;
@@ -30,7 +30,7 @@
     @ApiOperation(value = "用户退出")
     @PostMapping("/logout")
     public CommonResult logout(){
-
+        sysLoginService.logout();
         return CommonResult.success();
     }
 
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/controller/app/AppPaperStudentController.java
similarity index 88%
rename from exam-admin/src/main/java/com/gkhy/exam/admin/app/AppPaperStudentController.java
rename to exam-admin/src/main/java/com/gkhy/exam/admin/controller/app/AppPaperStudentController.java
index f9f71ab..9eab748 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppPaperStudentController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/app/AppPaperStudentController.java
@@ -1,4 +1,4 @@
-package com.gkhy.exam.admin.app;
+package com.gkhy.exam.admin.controller.app;
 
 
 import com.gkhy.exam.common.api.CommonResult;
@@ -60,11 +60,10 @@
     @PreAuthorize("hasAnyAuthority('train:exam:student')")
     @ApiOperation(value = "结束考试")
     @ApiImplicitParams({
-            @ApiImplicitParam(paramType = "body", name = "paperId", dataType = "long", required = true, value = "试卷id"),
-            @ApiImplicitParam(paramType = "body", name = "studentId", dataType = "long", required = true, value = "学员id")
+            @ApiImplicitParam(paramType = "body", name = "id", dataType = "long", required = true, value = "学员与试卷关系id")
     })
     @PostMapping(value = { "/endExam" })
-    public CommonResult endExam(ExPaperStudent paperStudent)
+    public CommonResult endExam(@RequestBody ExPaperStudent paperStudent)
     {
         paperStudentService.endExam(paperStudent);
         return CommonResult.success();
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/controller/app/AppPhaseStudentController.java
similarity index 97%
rename from exam-admin/src/main/java/com/gkhy/exam/admin/app/AppPhaseStudentController.java
rename to exam-admin/src/main/java/com/gkhy/exam/admin/controller/app/AppPhaseStudentController.java
index 515568d..4fe08d1 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppPhaseStudentController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/app/AppPhaseStudentController.java
@@ -1,4 +1,4 @@
-package com.gkhy.exam.admin.app;
+package com.gkhy.exam.admin.controller.app;
 
 
 import com.gkhy.exam.common.api.CommonResult;
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/controller/app/AppQuestionBankController.java
similarity index 97%
rename from exam-admin/src/main/java/com/gkhy/exam/admin/app/AppQuestionBankController.java
rename to exam-admin/src/main/java/com/gkhy/exam/admin/controller/app/AppQuestionBankController.java
index a74f3bb..547e0c2 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppQuestionBankController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/app/AppQuestionBankController.java
@@ -1,4 +1,4 @@
-package com.gkhy.exam.admin.app;
+package com.gkhy.exam.admin.controller.app;
 
 
 import com.gkhy.exam.common.annotation.RepeatSubmit;
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/controller/app/AppQuestionController.java
similarity index 90%
rename from exam-admin/src/main/java/com/gkhy/exam/admin/app/AppQuestionController.java
rename to exam-admin/src/main/java/com/gkhy/exam/admin/controller/app/AppQuestionController.java
index 79b0722..d770cb0 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppQuestionController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/app/AppQuestionController.java
@@ -1,4 +1,4 @@
-package com.gkhy.exam.admin.app;
+package com.gkhy.exam.admin.controller.app;
 
 
 import com.gkhy.exam.common.api.CommonResult;
@@ -32,15 +32,14 @@
     private ExQuestionService questionService;
 
     @PreAuthorize("hasAnyAuthority('train:exam:student')")
-    @ApiOperation(value = "刷题获取题目ID列表")
+    @ApiOperation(value = "刷题根据题库id获取题目ID列表")
     @ApiImplicitParams({
-            @ApiImplicitParam(paramType = "query", name = "bankId", dataType = "long", required = false, value = "题库id"),
-            @ApiImplicitParam(paramType = "query", name = "exercistType", dataType = "int", required = false, value = "练习方式:1随机,2顺序")
+            @ApiImplicitParam(paramType = "query", name = "bankId", dataType = "long", required = false, value = "题库id")
     })
     @GetMapping(value = { "/getExerciseQuestionList" })
-    public CommonResult getExerciseQuestionList(@RequestParam(required = true) Long bankId,  @RequestParam(required = true)Integer exerciseType)
+    public CommonResult getExerciseQuestionList(@RequestParam(required = true) Long bankId)
     {
-        return CommonResult.success(questionService.getExerciseQuestionList(bankId,exerciseType));
+        return CommonResult.success(questionService.getExerciseQuestionList(bankId));
     }
 
     @PreAuthorize("hasAnyAuthority('train:exam:student')")
@@ -67,7 +66,7 @@
 
 
     @PreAuthorize("hasAnyAuthority('train:exam:student')")
-    @ApiOperation(value = "刷题获取错题题目ID列表")
+    @ApiOperation(value = "刷题根据题库id获取错题题目ID列表")
     @ApiImplicitParams({
             @ApiImplicitParam(paramType = "query", name = "bankId", dataType = "long", required = false, value = "题库id")
     })
@@ -79,7 +78,7 @@
 
 
     @PreAuthorize("hasAnyAuthority('train:exam:student')")
-    @ApiOperation(value = "考试获取题目ID列表(考试完成返回错对,未完成则不返回)")
+    @ApiOperation(value = "考试获取题目ID列表(考试完成返回错对,未完成则返回是否答题状态)")
     @ApiImplicitParams({
             @ApiImplicitParam(paramType = "query", name = "bankId", dataType = "long", required = false, value = "考卷id"),
             @ApiImplicitParam(paramType = "query", name = "viewType", dataType = "int", required = false, value = "查看方式:1考试,2查看")
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/controller/app/AppResourceController.java
similarity index 95%
rename from exam-admin/src/main/java/com/gkhy/exam/admin/app/AppResourceController.java
rename to exam-admin/src/main/java/com/gkhy/exam/admin/controller/app/AppResourceController.java
index 7499f14..9f01a8e 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppResourceController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/app/AppResourceController.java
@@ -1,4 +1,4 @@
-package com.gkhy.exam.admin.app;
+package com.gkhy.exam.admin.controller.app;
 
 
 import com.gkhy.exam.common.api.CommonResult;
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/controller/app/AppStudentAnswerController.java
similarity index 96%
rename from exam-admin/src/main/java/com/gkhy/exam/admin/app/AppStudentAnswerController.java
rename to exam-admin/src/main/java/com/gkhy/exam/admin/controller/app/AppStudentAnswerController.java
index e622a83..51614e7 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppStudentAnswerController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/app/AppStudentAnswerController.java
@@ -1,4 +1,4 @@
-package com.gkhy.exam.admin.app;
+package com.gkhy.exam.admin.controller.app;
 
 
 import com.gkhy.exam.common.api.CommonResult;
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/controller/app/AppStudentController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/app/AppStudentController.java
new file mode 100644
index 0000000..bc4aa3c
--- /dev/null
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/app/AppStudentController.java
@@ -0,0 +1,43 @@
+package com.gkhy.exam.admin.controller.app;
+
+
+import com.gkhy.exam.common.api.CommonResult;
+import com.gkhy.exam.system.domain.ExStudent;
+import com.gkhy.exam.system.service.ExStudentService;
+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.*;
+
+/**
+ * <p>
+ * 学员前端控制器
+ * </p>
+ *
+ * @author kzy
+ * @since 2024-06-06 13:53:17
+ */
+@Api(tags = "APP学员前端控制器")
+@RestController
+@RequestMapping("/app/student")
+public class AppStudentController {
+    @Autowired
+    private ExStudentService studentService;
+
+    @PreAuthorize("hasAnyAuthority('train:exam:student')")
+    @ApiOperation(value = "根据id获取学员信息")
+    @GetMapping(value = { "/{studentId}" })
+    public CommonResult getStudentInfo(@PathVariable(value = "studentId", required = true) Long studentId)
+    {
+        return CommonResult.success(studentService.selectStudentById(studentId));
+    }
+
+    @PreAuthorize("hasAnyAuthority('train:exam:student')")
+    @ApiOperation(value = "重置密码")
+    @PutMapping(value = "/resetPwd")
+    public CommonResult restPwd(@RequestBody ExStudent student){
+        studentService.resetUserPwd(student);
+        return CommonResult.success();
+    }
+}
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/controller/app/AppStudentStudyController.java
similarity index 89%
rename from exam-admin/src/main/java/com/gkhy/exam/admin/app/AppStudentStudyController.java
rename to exam-admin/src/main/java/com/gkhy/exam/admin/controller/app/AppStudentStudyController.java
index 25ecdc0..dc38562 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/app/AppStudentStudyController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/app/AppStudentStudyController.java
@@ -1,6 +1,7 @@
-package com.gkhy.exam.admin.app;
+package com.gkhy.exam.admin.controller.app;
 
 
+import com.gkhy.exam.common.annotation.RepeatSubmit;
 import com.gkhy.exam.common.api.CommonResult;
 import com.gkhy.exam.system.domain.ExStudentStudy;
 import com.gkhy.exam.system.service.ExStudentStudyService;
@@ -28,6 +29,7 @@
     @Autowired
     private ExStudentStudyService studentStudyService;
 
+    @RepeatSubmit
     @PreAuthorize("hasAnyAuthority('train:exam:student')")
     @ApiOperation(value = "新增学习记录")
     @PostMapping
@@ -47,6 +49,7 @@
     })
     @PostMapping("/progress")
     public CommonResult progress(@RequestBody ExStudentStudy studentStudy){
+        System.out.println("progress info:"+studentStudy.getId()+","+studentStudy.getPhaseId()+","+studentStudy.getPeriodId()+","+studentStudy.getStudentId());
         studentStudyService.progress(studentStudy);
         return CommonResult.success();
     }
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/monitor/SysLogininforController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/monitor/SysLogininforController.java
similarity index 96%
rename from exam-admin/src/main/java/com/gkhy/exam/admin/monitor/SysLogininforController.java
rename to exam-admin/src/main/java/com/gkhy/exam/admin/controller/monitor/SysLogininforController.java
index 16a6ee9..8dde5f9 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/monitor/SysLogininforController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/monitor/SysLogininforController.java
@@ -1,4 +1,4 @@
-package com.gkhy.exam.admin.monitor;
+package com.gkhy.exam.admin.controller.monitor;
 
 /**
  * 系统访问记录
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/monitor/SysOperLogController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/monitor/SysOperLogController.java
similarity index 96%
rename from exam-admin/src/main/java/com/gkhy/exam/admin/monitor/SysOperLogController.java
rename to exam-admin/src/main/java/com/gkhy/exam/admin/controller/monitor/SysOperLogController.java
index be47184..b43aae0 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/monitor/SysOperLogController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/monitor/SysOperLogController.java
@@ -1,4 +1,4 @@
-package com.gkhy.exam.admin.monitor;
+package com.gkhy.exam.admin.controller.monitor;
 
 import com.gkhy.exam.common.annotation.Log;
 import com.gkhy.exam.common.api.CommonResult;
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/system/CaptchaController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/system/CaptchaController.java
similarity index 98%
rename from exam-admin/src/main/java/com/gkhy/exam/admin/system/CaptchaController.java
rename to exam-admin/src/main/java/com/gkhy/exam/admin/controller/system/CaptchaController.java
index c17fbb5..f603c3f 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/system/CaptchaController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/system/CaptchaController.java
@@ -1,4 +1,4 @@
-package com.gkhy.exam.admin.system;
+package com.gkhy.exam.admin.controller.system;
 
 import cn.hutool.core.codec.Base64;
 import cn.hutool.core.lang.UUID;
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/controller/system/SysCarouselController.java
similarity index 98%
rename from exam-admin/src/main/java/com/gkhy/exam/admin/system/SysCarouselController.java
rename to exam-admin/src/main/java/com/gkhy/exam/admin/controller/system/SysCarouselController.java
index 69f8d5e..97ba81e 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysCarouselController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/system/SysCarouselController.java
@@ -1,4 +1,4 @@
-package com.gkhy.exam.admin.system;
+package com.gkhy.exam.admin.controller.system;
 
 
 import com.gkhy.exam.common.annotation.Log;
@@ -48,6 +48,7 @@
         return CommonResult.success(carouselService.selectCarouselById(carouselId));
     }
 
+
     @RepeatSubmit
     @PreAuthorize("hasAnyAuthority('train:exam:system')")
     @Log(title = "轮播图管理", businessType = BusinessType.INSERT)
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/controller/system/SysCategoryController.java
similarity index 97%
rename from exam-admin/src/main/java/com/gkhy/exam/admin/system/SysCategoryController.java
rename to exam-admin/src/main/java/com/gkhy/exam/admin/controller/system/SysCategoryController.java
index 3dee02d..c58bfb9 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysCategoryController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/system/SysCategoryController.java
@@ -1,4 +1,4 @@
-package com.gkhy.exam.admin.system;
+package com.gkhy.exam.admin.controller.system;
 
 
 import com.gkhy.exam.common.annotation.Log;
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/controller/system/SysCommonController.java
similarity index 94%
rename from exam-admin/src/main/java/com/gkhy/exam/admin/system/SysCommonController.java
rename to exam-admin/src/main/java/com/gkhy/exam/admin/controller/system/SysCommonController.java
index 2fc11ca..19ed39a 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysCommonController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/system/SysCommonController.java
@@ -1,4 +1,4 @@
-package com.gkhy.exam.admin.system;
+package com.gkhy.exam.admin.controller.system;
 
 import com.gkhy.exam.common.annotation.RepeatSubmit;
 import com.gkhy.exam.common.api.CommonResult;
@@ -74,4 +74,11 @@
     }
 
 
+
+
+    @GetMapping("/importExcel")
+    public CommonResult importExcel() throws Exception {
+        commonService.importStudent();
+        return CommonResult.success();
+    }
 }
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/controller/system/SysCompanyController.java
similarity index 98%
rename from exam-admin/src/main/java/com/gkhy/exam/admin/system/SysCompanyController.java
rename to exam-admin/src/main/java/com/gkhy/exam/admin/controller/system/SysCompanyController.java
index 01410ef..3de34ce 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysCompanyController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/system/SysCompanyController.java
@@ -1,4 +1,4 @@
-package com.gkhy.exam.admin.system;
+package com.gkhy.exam.admin.controller.system;
 
 
 import com.gkhy.exam.common.annotation.Log;
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysConfigController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/system/SysConfigController.java
similarity index 97%
rename from exam-admin/src/main/java/com/gkhy/exam/admin/system/SysConfigController.java
rename to exam-admin/src/main/java/com/gkhy/exam/admin/controller/system/SysConfigController.java
index acb8925..8770e5e 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysConfigController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/system/SysConfigController.java
@@ -1,4 +1,4 @@
-package com.gkhy.exam.admin.system;
+package com.gkhy.exam.admin.controller.system;
 
 //@Api(tags = "系统配置前端控制器")
 //@RestController
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/controller/system/SysDictDataController.java
similarity index 98%
rename from exam-admin/src/main/java/com/gkhy/exam/admin/system/SysDictDataController.java
rename to exam-admin/src/main/java/com/gkhy/exam/admin/controller/system/SysDictDataController.java
index 6242552..1fda3ca 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysDictDataController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/system/SysDictDataController.java
@@ -1,4 +1,4 @@
-package com.gkhy.exam.admin.system;
+package com.gkhy.exam.admin.controller.system;
 
 import com.gkhy.exam.common.annotation.Log;
 import com.gkhy.exam.common.annotation.RepeatSubmit;
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/controller/system/SysDictTypeController.java
similarity index 98%
rename from exam-admin/src/main/java/com/gkhy/exam/admin/system/SysDictTypeController.java
rename to exam-admin/src/main/java/com/gkhy/exam/admin/controller/system/SysDictTypeController.java
index 505c2a3..65bcf92 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysDictTypeController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/system/SysDictTypeController.java
@@ -1,4 +1,4 @@
-package com.gkhy.exam.admin.system;
+package com.gkhy.exam.admin.controller.system;
 
 import com.gkhy.exam.common.annotation.Log;
 import com.gkhy.exam.common.annotation.RepeatSubmit;
diff --git a/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysLoginController.java b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/system/SysLoginController.java
similarity index 95%
rename from exam-admin/src/main/java/com/gkhy/exam/admin/system/SysLoginController.java
rename to exam-admin/src/main/java/com/gkhy/exam/admin/controller/system/SysLoginController.java
index bc9cee1..91ba831 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysLoginController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/system/SysLoginController.java
@@ -1,4 +1,4 @@
-package com.gkhy.exam.admin.system;
+package com.gkhy.exam.admin.controller.system;
 
 
 import com.gkhy.exam.common.api.CommonResult;
@@ -30,7 +30,7 @@
     @ApiOperation(value = "用户退出")
     @PostMapping("/logout")
     public CommonResult logout(){
-
+        sysLoginService.logout();
         return CommonResult.success();
     }
 
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/controller/system/SysNoticeController.java
similarity index 97%
rename from exam-admin/src/main/java/com/gkhy/exam/admin/system/SysNoticeController.java
rename to exam-admin/src/main/java/com/gkhy/exam/admin/controller/system/SysNoticeController.java
index 44f4239..e2d9106 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysNoticeController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/system/SysNoticeController.java
@@ -1,4 +1,4 @@
-package com.gkhy.exam.admin.system;
+package com.gkhy.exam.admin.controller.system;
 
 import com.gkhy.exam.common.annotation.Log;
 import com.gkhy.exam.common.annotation.RepeatSubmit;
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/controller/system/SysProfileController.java
similarity index 98%
rename from exam-admin/src/main/java/com/gkhy/exam/admin/system/SysProfileController.java
rename to exam-admin/src/main/java/com/gkhy/exam/admin/controller/system/SysProfileController.java
index 80f6ed3..55d540e 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysProfileController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/system/SysProfileController.java
@@ -1,4 +1,4 @@
-package com.gkhy.exam.admin.system;
+package com.gkhy.exam.admin.controller.system;
 
 import cn.hutool.core.codec.Base64;
 import com.gkhy.exam.common.annotation.Log;
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/controller/system/SysUserController.java
similarity index 95%
rename from exam-admin/src/main/java/com/gkhy/exam/admin/system/SysUserController.java
rename to exam-admin/src/main/java/com/gkhy/exam/admin/controller/system/SysUserController.java
index 32a1ed2..1da8aa6 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/system/SysUserController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/system/SysUserController.java
@@ -1,4 +1,4 @@
-package com.gkhy.exam.admin.system;
+package com.gkhy.exam.admin.controller.system;
 
 import com.gkhy.exam.common.annotation.Log;
 import com.gkhy.exam.common.annotation.RepeatSubmit;
@@ -24,7 +24,7 @@
 
   //  @PreAuthorize("hasAuthority('train:exam:company')")
  //   @PreAuthorize("hasAnyAuthority('train:exam:system','train:exam:company')")
-  @PreAuthorize("hasAnyAuthority('train:exam:system','train:exam:company','train:exam:depart','train:exam:workshop','train:exam:other')")
+    @PreAuthorize("hasAnyAuthority('train:exam:system','train:exam:company','train:exam:depart','train:exam:workshop','train:exam:other')")
     @ApiOperation(value = "用户列表(分页)")
     @ApiImplicitParams({
             @ApiImplicitParam(paramType = "query", name = "pageNum", dataType = "int", required = false, value = "当前页,默认1"),
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/controller/web/ExCompanyPeriodController.java
similarity index 97%
rename from exam-admin/src/main/java/com/gkhy/exam/admin/web/ExCompanyPeriodController.java
rename to exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExCompanyPeriodController.java
index b3c3740..172188c 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExCompanyPeriodController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExCompanyPeriodController.java
@@ -1,4 +1,4 @@
-package com.gkhy.exam.admin.web;
+package com.gkhy.exam.admin.controller.web;
 
 
 import com.gkhy.exam.common.annotation.Log;
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/controller/web/ExCourseChapterController.java
similarity index 98%
rename from exam-admin/src/main/java/com/gkhy/exam/admin/web/ExCourseChapterController.java
rename to exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExCourseChapterController.java
index a2f92e8..cd5bfa6 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExCourseChapterController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExCourseChapterController.java
@@ -1,4 +1,4 @@
-package com.gkhy.exam.admin.web;
+package com.gkhy.exam.admin.controller.web;
 
 
 import com.gkhy.exam.common.annotation.Log;
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/controller/web/ExCourseChapterPeriodController.java
similarity index 98%
rename from exam-admin/src/main/java/com/gkhy/exam/admin/web/ExCourseChapterPeriodController.java
rename to exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExCourseChapterPeriodController.java
index bb9a5f7..5642650 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExCourseChapterPeriodController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExCourseChapterPeriodController.java
@@ -1,4 +1,4 @@
-package com.gkhy.exam.admin.web;
+package com.gkhy.exam.admin.controller.web;
 
 
 import com.gkhy.exam.common.annotation.Log;
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/controller/web/ExCourseController.java
similarity index 98%
rename from exam-admin/src/main/java/com/gkhy/exam/admin/web/ExCourseController.java
rename to exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExCourseController.java
index c88e15f..5df319a 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExCourseController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExCourseController.java
@@ -1,4 +1,4 @@
-package com.gkhy.exam.admin.web;
+package com.gkhy.exam.admin.controller.web;
 
 
 import com.gkhy.exam.common.annotation.Log;
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/controller/web/ExCoursePhaseController.java
similarity index 96%
rename from exam-admin/src/main/java/com/gkhy/exam/admin/web/ExCoursePhaseController.java
rename to exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExCoursePhaseController.java
index c32a469..2d4e71d 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExCoursePhaseController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExCoursePhaseController.java
@@ -1,4 +1,4 @@
-package com.gkhy.exam.admin.web;
+package com.gkhy.exam.admin.controller.web;
 
 
 import com.gkhy.exam.common.annotation.Log;
@@ -65,7 +65,7 @@
     }
 
     @RepeatSubmit
-    @Log(title = "批次管理", businessType = BusinessType.UPDATE)
+    @Log(title = "批次管理", businessType = BusinessType.DELETE)
     @ApiOperation(value = "删除批次")
     @DeleteMapping(value = { "/{phaseId}" })
     public CommonResult delete(@PathVariable(value = "phaseId", required = true) Long 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/controller/web/ExExamPaperController.java
similarity index 86%
rename from exam-admin/src/main/java/com/gkhy/exam/admin/web/ExExamPaperController.java
rename to exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExExamPaperController.java
index 1e018ec..34bf842 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExExamPaperController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExExamPaperController.java
@@ -1,4 +1,4 @@
-package com.gkhy.exam.admin.web;
+package com.gkhy.exam.admin.controller.web;
 
 
 import com.gkhy.exam.common.annotation.Log;
@@ -12,6 +12,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.*;
 
@@ -48,6 +49,7 @@
     }
 
     @RepeatSubmit
+    @PreAuthorize("hasAnyAuthority('train:exam:company','train:exam:depart','train:exam:workshop','train:exam:other')")
     @Log(title = "试卷管理", businessType = BusinessType.INSERT)
     @ApiOperation(value = "新增试卷")
     @PostMapping
@@ -56,6 +58,7 @@
     }
 
     @RepeatSubmit
+    @PreAuthorize("hasAnyAuthority('train:exam:company','train:exam:depart','train:exam:workshop','train:exam:other')")
     @Log(title = "试卷管理", businessType = BusinessType.UPDATE)
     @ApiOperation(value = "编辑试卷")
     @PutMapping
@@ -64,7 +67,8 @@
     }
 
     @RepeatSubmit
-    @Log(title = "试卷管理", businessType = BusinessType.UPDATE)
+    @PreAuthorize("hasAnyAuthority('train:exam:company','train:exam:depart','train:exam:workshop','train:exam:other')")
+    @Log(title = "试卷管理", businessType = BusinessType.DELETE)
     @ApiOperation(value = "删除试卷")
     @DeleteMapping(value = { "/{paperId}" })
     public CommonResult delete(@PathVariable(value = "paperId", required = true) Long paperId){
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/controller/web/ExExamRecordController.java
similarity index 98%
rename from exam-admin/src/main/java/com/gkhy/exam/admin/web/ExExamRecordController.java
rename to exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExExamRecordController.java
index 33b619c..609724f 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExExamRecordController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExExamRecordController.java
@@ -1,4 +1,4 @@
-package com.gkhy.exam.admin.web;
+package com.gkhy.exam.admin.controller.web;
 
 
 import com.gkhy.exam.common.annotation.Log;
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/controller/web/ExPaperStudentController.java
similarity index 77%
rename from exam-admin/src/main/java/com/gkhy/exam/admin/web/ExPaperStudentController.java
rename to exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExPaperStudentController.java
index 20b2a6a..9cbf75b 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExPaperStudentController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExPaperStudentController.java
@@ -1,4 +1,4 @@
-package com.gkhy.exam.admin.web;
+package com.gkhy.exam.admin.controller.web;
 
 
 import com.gkhy.exam.common.annotation.Log;
@@ -6,6 +6,8 @@
 import com.gkhy.exam.common.api.CommonResult;
 import com.gkhy.exam.common.enums.BusinessType;
 import com.gkhy.exam.system.domain.ExPaperStudent;
+import com.gkhy.exam.system.domain.vo.BatchPaperStudentVO;
+import com.gkhy.exam.system.domain.vo.ExPaperStudentVO;
 import com.gkhy.exam.system.service.ExPaperStudentService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiImplicitParam;
@@ -17,7 +19,6 @@
 
 import java.util.Collections;
 import java.util.List;
-import java.util.Map;
 
 /**
  * <p>
@@ -45,6 +46,13 @@
         return CommonResult.success(paperStudentService.selectPaperStudentList(paperStudent));
     }
 
+    @ApiOperation(value = "根据id查询学员试卷信息")
+    @GetMapping(value = { "/getPaperStudentById" })
+    public CommonResult getPaperStudentById(@RequestParam(value = "paperStudentId", required = true) Long paperStudentId)
+    {
+        return CommonResult.success(paperStudentService.selectPaperStudentById(paperStudentId));
+    }
+
     @RepeatSubmit
     @Log(title = "试卷与学员关系管理", businessType = BusinessType.INSERT)
     @ApiOperation(value = "新增学员")
@@ -55,15 +63,10 @@
 
     @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(@RequestBody Map<String,Object> paperStudentMap){
-        return CommonResult.success(paperStudentService.batchAddPaperStudent(paperStudentMap));
+    public CommonResult batchAdd(@Validated @RequestBody BatchPaperStudentVO batchPaperStudent){
+        return CommonResult.success(paperStudentService.batchAddPaperStudent(batchPaperStudent));
     }
 
     @RepeatSubmit
@@ -78,7 +81,7 @@
     @Log(title = "试卷与学员关系管理", businessType = BusinessType.DELETE)
     @ApiOperation(value = "批量删除学员")
     @DeleteMapping(value = { "/batchDelete" })
-    public CommonResult batchDelete( List<Long> paperStudentIds){
+    public CommonResult batchDelete(@RequestBody List<Long> paperStudentIds){
         paperStudentService.batchDeletePaperStudent(paperStudentIds);
         return CommonResult.success();
     }
@@ -90,4 +93,13 @@
         paperStudentService.checkStudentUnique(Collections.singletonList(paperStudent));
         return CommonResult.success();
     }
+
+
+    @ApiOperation(value = "提交批改试卷")
+    @PostMapping("/doReview")
+    public CommonResult doReview(@RequestBody ExPaperStudentVO paperStudentVO)
+    {
+        paperStudentService.doReview(paperStudentVO);
+        return CommonResult.success();
+    }
 }
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/controller/web/ExPhaseStudentController.java
similarity index 95%
rename from exam-admin/src/main/java/com/gkhy/exam/admin/web/ExPhaseStudentController.java
rename to exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExPhaseStudentController.java
index 512a48c..0bcd63d 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExPhaseStudentController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExPhaseStudentController.java
@@ -1,4 +1,4 @@
-package com.gkhy.exam.admin.web;
+package com.gkhy.exam.admin.controller.web;
 
 
 import com.gkhy.exam.common.annotation.Log;
@@ -69,10 +69,10 @@
     }
 
     @RepeatSubmit
-    @Log(title = "批次与学员关系管理", businessType = BusinessType.UPDATE)
+    @Log(title = "批次与学员关系管理", businessType = BusinessType.DELETE)
     @ApiOperation(value = "批量删除学员")
     @DeleteMapping(value = { "/batchDelete" })
-    public CommonResult batchDelete( List<Long> phaseStudentIds){
+    public CommonResult batchDelete(@RequestBody List<Long> phaseStudentIds){
         phaseStudentService.batchDeletePhaseStudent(phaseStudentIds);
         return CommonResult.success();
     }
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/controller/web/ExQuestionBankController.java
similarity index 98%
rename from exam-admin/src/main/java/com/gkhy/exam/admin/web/ExQuestionBankController.java
rename to exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExQuestionBankController.java
index e39c890..882673a 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExQuestionBankController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExQuestionBankController.java
@@ -1,4 +1,4 @@
-package com.gkhy.exam.admin.web;
+package com.gkhy.exam.admin.controller.web;
 
 
 import com.gkhy.exam.common.annotation.Log;
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/controller/web/ExQuestionController.java
similarity index 96%
rename from exam-admin/src/main/java/com/gkhy/exam/admin/web/ExQuestionController.java
rename to exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExQuestionController.java
index f18c2e9..9f70d58 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExQuestionController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExQuestionController.java
@@ -1,4 +1,4 @@
-package com.gkhy.exam.admin.web;
+package com.gkhy.exam.admin.controller.web;
 
 
 import com.gkhy.exam.common.annotation.Log;
@@ -34,7 +34,7 @@
     @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 = "bankId", dataType = "long", required = true, value = "题库id")
+            @ApiImplicitParam(paramType = "query", name = "bankId", dataType = "long", required = false, value = "题库id")
     })
     @GetMapping("/list")
     public CommonResult list(ExQuestion question){
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/controller/web/ExResourceController.java
similarity index 98%
rename from exam-admin/src/main/java/com/gkhy/exam/admin/web/ExResourceController.java
rename to exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExResourceController.java
index 4fa831b..1a52efa 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExResourceController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExResourceController.java
@@ -1,4 +1,4 @@
-package com.gkhy.exam.admin.web;
+package com.gkhy.exam.admin.controller.web;
 
 
 import com.gkhy.exam.common.annotation.Log;
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/controller/web/ExStatisticController.java
similarity index 84%
rename from exam-admin/src/main/java/com/gkhy/exam/admin/web/ExStatisticController.java
rename to exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExStatisticController.java
index 6425dfe..f504f97 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExStatisticController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExStatisticController.java
@@ -1,4 +1,4 @@
-package com.gkhy.exam.admin.web;
+package com.gkhy.exam.admin.controller.web;
 
 
 import com.gkhy.exam.common.api.CommonResult;
@@ -8,6 +8,7 @@
 import io.swagger.annotations.ApiImplicitParams;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.format.annotation.DateTimeFormat;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestParam;
@@ -40,7 +41,7 @@
             @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) {
+    public CommonResult companyStatistic(@RequestParam(required = true,defaultValue = "1") Integer type, @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date startTime, @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")Date endTime, @RequestParam(required = false) Long companyId) {
         return CommonResult.success(statisticService.companyStatic(companyId, startTime, endTime,type));
     }
 
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/controller/web/ExStudentController.java
similarity index 77%
rename from exam-admin/src/main/java/com/gkhy/exam/admin/web/ExStudentController.java
rename to exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExStudentController.java
index b082d15..cdab661 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExStudentController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExStudentController.java
@@ -1,4 +1,4 @@
-package com.gkhy.exam.admin.web;
+package com.gkhy.exam.admin.controller.web;
 
 
 import com.gkhy.exam.common.annotation.Log;
@@ -12,8 +12,11 @@
 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.*;
+
+import java.util.Map;
 
 /**
  * <p>
@@ -92,6 +95,27 @@
     @ApiOperation(value = "校验身份证是否为一")
     @PostMapping(value = "/checkIdNoUnique")
     public CommonResult checkIdNoUnique(@RequestBody ExStudent student){
-        return CommonResult.success(studentService.checkIdNoUnique(student));
+        return CommonResult.success(studentService.checkIdNoUnique(student.getIdNo()));
     }
+
+
+    @ApiOperation(value = "学员企业归属变更")
+    @ApiImplicitParams({
+            @ApiImplicitParam(paramType = "body", name = "studentId", dataType = "long", required = true, value = "学员id"),
+            @ApiImplicitParam(paramType = "body", name = "companyId", dataType = "long", required = true, value = "公司id")
+    })
+    @PreAuthorize("hasAnyAuthority('train:exam:system','train:exam:company')")
+    @PostMapping(value = "/changeStudentCompany")
+    public CommonResult changeStudentCompany(@RequestBody Map<String,Long> bodyMap){
+        studentService.changeStudentCompany(bodyMap);
+        return CommonResult.success();
+    }
+
+
+    @ApiOperation(value = "学员培训记录")
+    @GetMapping(value = "/trainRecord")
+    public CommonResult trainRecord(Long studentId){
+        return CommonResult.success(studentService.trainRecord(studentId));
+    }
+
 }
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/controller/web/ExStudentStudyController.java
similarity index 97%
rename from exam-admin/src/main/java/com/gkhy/exam/admin/web/ExStudentStudyController.java
rename to exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExStudentStudyController.java
index 470a514..9b657d8 100644
--- a/exam-admin/src/main/java/com/gkhy/exam/admin/web/ExStudentStudyController.java
+++ b/exam-admin/src/main/java/com/gkhy/exam/admin/controller/web/ExStudentStudyController.java
@@ -1,4 +1,4 @@
-package com.gkhy.exam.admin.web;
+package com.gkhy.exam.admin.controller.web;
 
 
 import com.gkhy.exam.common.annotation.Log;
diff --git a/exam-admin/src/main/resources/application-dev.yml b/exam-admin/src/main/resources/application-dev.yml
index 198c6b9..b3b0590 100644
--- a/exam-admin/src/main/resources/application-dev.yml
+++ b/exam-admin/src/main/resources/application-dev.yml
@@ -16,7 +16,7 @@
         password:
       initialSize: 5 #连接池初始化大小
       minIdle: 10 #最小空闲连接数
-      maxActive: 20 #最大连接数
+      maxActive: 50 #最大连接数
       # 配置获取连接等待超时的时间
       maxWait: 60000
       # 配置连接超时时间
@@ -73,9 +73,7 @@
   level:
     root: INFO
     org:
-      com.nms.swspkmas_standalone: DEBUG
-  file:
-    name: logs/nms-kaoshi.log
+      com.gkhy.exam: DEBUG
 
 swagger:
   enabled: true
@@ -84,46 +82,4 @@
   endpoint: http://192.168.2.16:9000/ #Minio服务所在地址
   bucketName: trainexam #存储桶名称
   accessKey: JuHGtYXvgJdeaPHcu5AI #访问的key
-  secretKey: mQhUsIYnD696ZFI2sJ6eQ77tmmoe9TTUavFg9Ien #访问的秘钥
-
-
-
-
-
-version: '3.9'
-services:
-  kele_mysql:
-    restart: always
-    image: mysql:5.6
-    volumes:
-      - ./data/mysql:/var/lib/mysql
-      - ./conf/mysql/:/etc/mysql/conf.d
-    ports:
-      - "3306:3306"
-    environment:
-      - MYSQL_DATABASE=imooc
-      - MYSQL_ROOT_PASSWORD=root
-
-  kele_nginx:
-    restart: always
-    image: nginx
-    ports:
-      - "8001:80"
-    volumes:
-      - ./conf/nginx/mx_nginx.conf:/etc/nginx/conf.d/mx_nginx.conf
-    volumes_from:
-      - kele_imooc
-    links:
-      - kele_imooc:web
-
-  kele_imooc:
-    restart: always
-    build: .
-    ports:
-      - "8000:8000"
-    volumes:
-      - .:/imooc
-    links:
-      - kele_mysql:mysql
-    command: uwsgi -s :8000 -w imooc.wsgi -p 3
-
+  secretKey: mQhUsIYnD696ZFI2sJ6eQ77tmmoe9TTUavFg9Ien #访问的秘钥
\ No newline at end of file
diff --git a/exam-admin/src/main/resources/application-guotai.yml b/exam-admin/src/main/resources/application-guotai.yml
new file mode 100644
index 0000000..ea00653
--- /dev/null
+++ b/exam-admin/src/main/resources/application-guotai.yml
@@ -0,0 +1,86 @@
+spring:
+  datasource:
+    type: com.alibaba.druid.pool.DruidDataSource
+    driverClassName: com.mysql.cj.jdbc.Driver
+    druid:
+      # 主库数据源
+      master:
+        url: jdbc:mysql://127.0.0.1:6361/train_exam?useUnicode=true&characterEncoding=utf-8&autoReconnect=true&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true&allowMultiQueries=true
+        username: root
+        password: HZjCbHGxiXy7cek4
+      # 从库数据源
+      slave:
+        enabled: false
+        url:
+        username:
+        password:
+      initialSize: 5 #连接池初始化大小
+      minIdle: 10 #最小空闲连接数
+      maxActive: 50 #最大连接数
+      # 配置获取连接等待超时的时间
+      maxWait: 60000
+      # 配置连接超时时间
+      connectTimeout: 30000
+      # 配置网络超时时间
+      socketTimeout: 60000
+      # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+      timeBetweenEvictionRunsMillis: 60000
+      # 配置一个连接在池中最小生存的时间,单位是毫秒
+      minEvictableIdleTimeMillis: 300000
+      # 配置一个连接在池中最大生存的时间,单位是毫秒
+      maxEvictableIdleTimeMillis: 900000
+      # 配置检测连接是否有效
+      validationQuery: SELECT 1 FROM DUAL
+      testWhileIdle: true
+      testOnBorrow: false
+      testOnReturn: false
+      web-stat-filter:
+        exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*" #不统计这些请求数据
+      stat-view-servlet: #访问监控网页的登录用户名和密码
+        login-username: druid
+        login-password: druid
+  #redis 配置
+  redis:
+    database: 4
+    host: 127.0.0.1
+    port: 6379
+    password: akj78avauba789a
+
+
+# mybatis-plus相关配置
+mybatis-plus:
+  # xml扫描,多个目录用逗号或者分号分隔(告诉 Mapper 所对应的 XML 文件位置)
+  mapper-locations: classpath*:mapper/**/*Mapper.xml
+  # 以下配置均有默认值,可以不设置
+  global-config:
+    db-config:
+      #主键类型 AUTO:"数据库ID自增" INPUT:"用户输入ID",ID_WORKER:"全局唯一ID (数字类型唯一ID)", UUID:"全局唯一ID UUID";
+      id-type: auto
+      #字段策略 IGNORED:"忽略判断"  NOT_NULL:"非 NULL 判断")  NOT_EMPTY:"非空判断"
+      field-strategy: NOT_EMPTY
+      #数据库类型
+      db-type: MYSQL
+  configuration:
+    # 是否开启自动驼峰命名规则映射:从数据库列名到Java属性驼峰命名的类似映射
+    map-underscore-to-camel-case: true
+    # 如果查询结果中包含空值的列,则 MyBatis 在映射的时候,不会映射这个字段
+    call-setters-on-nulls: true
+    # 这个配置会将执行的sql打印出来,在开发或测试的时候可以用
+    #log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
+
+
+logging:
+  level:
+    root: INFO
+    org:
+      com.gkhy.exam: INFO
+
+
+swagger:
+  enabled: false
+
+minio:
+  endpoint: http://106.15.95.149:9001/ #Minio服务所在地址
+  bucketName: trainexam #存储桶名称
+  accessKey: U9JW4xOeeUQOSR4f #访问的key
+  secretKey: iaqQV6twR9yDZiFAf2UYr5xZfESanZs3 #访问的秘钥
diff --git a/exam-admin/src/main/resources/application-prod.yml b/exam-admin/src/main/resources/application-prod.yml
new file mode 100644
index 0000000..906b0f9
--- /dev/null
+++ b/exam-admin/src/main/resources/application-prod.yml
@@ -0,0 +1,86 @@
+spring:
+  datasource:
+    type: com.alibaba.druid.pool.DruidDataSource
+    driverClassName: com.mysql.cj.jdbc.Driver
+    druid:
+      # 主库数据源
+      master:
+        url: jdbc:mysql://127.0.0.1:23306/train_exam?useUnicode=true&characterEncoding=utf-8&autoReconnect=true&serverTimezone=Asia/Beijing&useSSL=false&allowPublicKeyRetrieval=true&allowMultiQueries=true
+        username: root
+        password: 2farwL3yPXfbH2AP
+      # 从库数据源
+      slave:
+        enabled: false
+        url:
+        username:
+        password:
+      initialSize: 5 #连接池初始化大小
+      minIdle: 10 #最小空闲连接数
+      maxActive: 50 #最大连接数
+      # 配置获取连接等待超时的时间
+      maxWait: 60000
+      # 配置连接超时时间
+      connectTimeout: 30000
+      # 配置网络超时时间
+      socketTimeout: 60000
+      # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+      timeBetweenEvictionRunsMillis: 60000
+      # 配置一个连接在池中最小生存的时间,单位是毫秒
+      minEvictableIdleTimeMillis: 300000
+      # 配置一个连接在池中最大生存的时间,单位是毫秒
+      maxEvictableIdleTimeMillis: 900000
+      # 配置检测连接是否有效
+      validationQuery: SELECT 1 FROM DUAL
+      testWhileIdle: true
+      testOnBorrow: false
+      testOnReturn: false
+      web-stat-filter:
+        exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*" #不统计这些请求数据
+      stat-view-servlet: #访问监控网页的登录用户名和密码
+        login-username: druid
+        login-password: druid
+  #redis 配置
+  redis:
+    database: 0
+    host: 127.0.0.1
+    port: 6379
+    password:
+
+
+# mybatis-plus相关配置
+mybatis-plus:
+  # xml扫描,多个目录用逗号或者分号分隔(告诉 Mapper 所对应的 XML 文件位置)
+  mapper-locations: classpath*:mapper/**/*Mapper.xml
+  # 以下配置均有默认值,可以不设置
+  global-config:
+    db-config:
+      #主键类型 AUTO:"数据库ID自增" INPUT:"用户输入ID",ID_WORKER:"全局唯一ID (数字类型唯一ID)", UUID:"全局唯一ID UUID";
+      id-type: auto
+      #字段策略 IGNORED:"忽略判断"  NOT_NULL:"非 NULL 判断")  NOT_EMPTY:"非空判断"
+      field-strategy: NOT_EMPTY
+      #数据库类型
+      db-type: MYSQL
+  configuration:
+    # 是否开启自动驼峰命名规则映射:从数据库列名到Java属性驼峰命名的类似映射
+    map-underscore-to-camel-case: true
+    # 如果查询结果中包含空值的列,则 MyBatis 在映射的时候,不会映射这个字段
+    call-setters-on-nulls: true
+    # 这个配置会将执行的sql打印出来,在开发或测试的时候可以用
+    #log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
+
+
+logging:
+  level:
+    root: INFO
+    org:
+      com.gkhy.exam: INFO
+
+
+swagger:
+  enabled: false
+
+minio:
+  endpoint: http://127.0.0.1:9000/ #Minio服务所在地址
+  bucketName: trainexam #存储桶名称
+  accessKey: nblxqRZXDvQ59HBH49rF #访问的key
+  secretKey: TR0IFphXPo0IObQCYgcJ0JOik21s40ey2MIMU8Rh #访问的秘钥
diff --git a/exam-admin/src/main/resources/application.yml b/exam-admin/src/main/resources/application.yml
index 801cfa5..e406ad7 100644
--- a/exam-admin/src/main/resources/application.yml
+++ b/exam-admin/src/main/resources/application.yml
@@ -2,7 +2,7 @@
   application:
     name: train_exam
   profiles:
-    active: dev
+    active: guotai
   servlet:
     multipart:
       enabled: true
@@ -18,6 +18,10 @@
   port: 8082
   servlet:
     context-path: /api
+  tomcat:
+    threads:
+      min-spare: 10
+      max: 200
 
 
 # 用户配置
@@ -36,3 +40,13 @@
   #获取ip地址开关
   addressEnabled: false
 
+
+# 防止XSS攻击
+xss:
+  # 过滤开关
+  enabled: true
+  # 排除链接(多个用逗号分隔)
+  excludes:
+  # 匹配链接
+  urlPatterns: /system/*,/manage/*
+
diff --git a/exam-admin/src/main/resources/db/migration/V20231016001_add_user.sql b/exam-admin/src/main/resources/db/migration/V20231016001_add_user.sql
index b160bee..207f24f 100644
--- a/exam-admin/src/main/resources/db/migration/V20231016001_add_user.sql
+++ b/exam-admin/src/main/resources/db/migration/V20231016001_add_user.sql
@@ -1,7 +1,6 @@
 -- ----------------------------
 -- 系统管理用户表
 -- ----------------------------
-drop table if exists `train_exam`.`sys_user`;
 CREATE TABLE `train_exam`.`sys_user`  (
 `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
 `username` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '登录账号',
@@ -10,7 +9,7 @@
 `phone` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '手机号码',
 `sex` tinyint NULL DEFAULT 2 COMMENT '用户性别(0男,1女,2未知,默认2)',
 `company_id` bigint(20) NULL DEFAULT NULL COMMENT '公司id',
-`parent_id` bigint(20) NULL DEFAULT NULL COMMENT '父级账号id',
+`parent_id` bigint(20) NULL DEFAULT 0 COMMENT '父级账号id',
 `password` varchar(80) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '密码',
 `status` tinyint NULL DEFAULT 0 COMMENT '账号状态(0正常,1停用,默认0)',
 `del_flag` tinyint NULL DEFAULT 0 COMMENT '删除标志(0代表存在,2代表删除,默认0)',
@@ -27,4 +26,4 @@
 UNIQUE INDEX `index_username`(`username`) USING BTREE
 ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '系统管理用户表' ROW_FORMAT = Dynamic;
 
-insert into sys_user values(1, 'admin', '国科鸿宇', 0, '15888888888', 0, null, '$2a$10$CrsAZufp851DxTmUBep7TOuUAESWdqlkrReAIR.4SHBIahl9exO6y',  0, 0, '127.0.0.1', sysdate(), sysdate(), 'admin', sysdate(), '', sysdate(), '管理员',0);
+insert into sys_user values(1, 'admin', '国科鸿宇', 0, '15888888888', 0, null,0, '$2a$10$CrsAZufp851DxTmUBep7TOuUAESWdqlkrReAIR.4SHBIahl9exO6y',  0, 0, '127.0.0.1', sysdate(), sysdate(), 'admin', sysdate(), '', sysdate(), '管理员',0);
diff --git a/exam-admin/src/main/resources/db/migration/V20231018009_dict_type.sql b/exam-admin/src/main/resources/db/migration/V20231018009_dict_type.sql
index 3b8db28..cb70984 100644
--- a/exam-admin/src/main/resources/db/migration/V20231018009_dict_type.sql
+++ b/exam-admin/src/main/resources/db/migration/V20231018009_dict_type.sql
@@ -2,7 +2,6 @@
 -- ----------------------------
 -- 字典类型表
 -- ----------------------------
-drop table if exists `train_exam`.`sys_dict_type`;
 CREATE TABLE `train_exam`.`sys_dict_type`  (
 `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT,
 `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '字典名称',
diff --git a/exam-admin/src/main/resources/db/migration/V20231018010_dict_data.sql b/exam-admin/src/main/resources/db/migration/V20231018010_dict_data.sql
index ade1087..12db86b 100644
--- a/exam-admin/src/main/resources/db/migration/V20231018010_dict_data.sql
+++ b/exam-admin/src/main/resources/db/migration/V20231018010_dict_data.sql
@@ -2,7 +2,6 @@
 -- ----------------------------
 -- 字典数据表
 -- ----------------------------
-drop table if exists `train_exam`.`sys_dict_data`;
 CREATE TABLE `train_exam`.`sys_dict_data`  (
 `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT,
 `sort` int NOT NULL DEFAULT 0 COMMENT '字典排序',
diff --git a/exam-admin/src/main/resources/db/migration/V20231110001_config.sql b/exam-admin/src/main/resources/db/migration/V20231110001_config.sql
index 11f84af..c8d0677 100644
--- a/exam-admin/src/main/resources/db/migration/V20231110001_config.sql
+++ b/exam-admin/src/main/resources/db/migration/V20231110001_config.sql
@@ -2,7 +2,6 @@
 -- ----------------------------
 -- 系统配置表
 -- ----------------------------
-drop table if exists `train_exam`.`sys_config`;
 CREATE TABLE `train_exam`.`sys_config`  (
 `id` bigint NOT NULL AUTO_INCREMENT,
 `name` varchar(100) NOT NULL COMMENT '参数名称',
diff --git a/exam-admin/src/main/resources/db/migration/V20240428001_notice.sql b/exam-admin/src/main/resources/db/migration/V20240428001_notice.sql
index e543a59..d82223c 100644
--- a/exam-admin/src/main/resources/db/migration/V20240428001_notice.sql
+++ b/exam-admin/src/main/resources/db/migration/V20240428001_notice.sql
@@ -2,7 +2,6 @@
 -- ----------------------------
 -- 系统通知表
 -- ----------------------------
-drop table if exists sys_notice;
 create table sys_notice (
 id        bigint NOT NULL AUTO_INCREMENT,
 title      varchar(50)     not null                   comment '公告标题',
diff --git a/exam-admin/src/main/resources/db/migration/V20240506001_ope_log.sql b/exam-admin/src/main/resources/db/migration/V20240506001_ope_log.sql
index ba92fa7..e26608a 100644
--- a/exam-admin/src/main/resources/db/migration/V20240506001_ope_log.sql
+++ b/exam-admin/src/main/resources/db/migration/V20240506001_ope_log.sql
@@ -2,7 +2,6 @@
 -- ----------------------------
 -- 操作日志表
 -- ----------------------------
-drop table if exists sys_oper_log;
 create table sys_oper_log (
 id           bigint(20)      not null auto_increment    comment '日志主键',
 title             varchar(50)     default ''                 comment '模块标题',
diff --git a/exam-admin/src/main/resources/db/migration/V20240510001_loginfor.sql b/exam-admin/src/main/resources/db/migration/V20240510001_loginfor.sql
index 17a4823..686f3fc 100644
--- a/exam-admin/src/main/resources/db/migration/V20240510001_loginfor.sql
+++ b/exam-admin/src/main/resources/db/migration/V20240510001_loginfor.sql
@@ -2,7 +2,6 @@
 -- ----------------------------
 -- 系统访问记录
 -- ----------------------------
-drop table if exists sys_logininfor;
 create table sys_logininfor (
 id           bigint(20)      not null auto_increment    comment '日志主键',
 user_name      varchar(50)    default ''                comment '用户账号',
diff --git a/exam-admin/src/main/resources/db/migration/V20240531001_student.sql b/exam-admin/src/main/resources/db/migration/V20240531001_student.sql
index 6048104..5d90622 100644
--- a/exam-admin/src/main/resources/db/migration/V20240531001_student.sql
+++ b/exam-admin/src/main/resources/db/migration/V20240531001_student.sql
@@ -2,7 +2,6 @@
 -- ----------------------------
 -- 学员表
 -- ----------------------------
-drop table if exists `train_exam`.`ex_student`;
 CREATE TABLE `train_exam`.`ex_student`  (
 `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
 `company_id` bigint(20) NOT NULL COMMENT '企业id',
diff --git a/exam-admin/src/main/resources/db/migration/V20240531002_company.sql b/exam-admin/src/main/resources/db/migration/V20240531002_company.sql
index b9b3ec6..6e5c414 100644
--- a/exam-admin/src/main/resources/db/migration/V20240531002_company.sql
+++ b/exam-admin/src/main/resources/db/migration/V20240531002_company.sql
@@ -2,16 +2,14 @@
 -- ----------------------------
 -- 企业表
 -- ----------------------------
-drop table if exists `train_exam`.`sys_company`;
 CREATE TABLE `train_exam`.`sys_company`  (
 `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
 `name` varchar(80) NOT NULL COMMENT '企业名称',
 `credit_code` varchar(30) NOT NULL COMMENT '企业信用代码',
 `major` varchar(30) NOT NULL COMMENT '负责人',
 `phone` varchar(11) NOT NULL COMMENT '联系电话',
-`remain_period` int NOT NULL DEFAULT 0 COMMENT '剩余课时(分)',
-`spend_period` int NOT NULL DEFAULT 0 COMMENT '已用课时(分)',
-`total_period` int NOT NULL DEFAULT 0 COMMENT '总课时(分)',
+`remain_period` bigint(20) NOT NULL DEFAULT 0 COMMENT '剩余课时(秒)',
+`total_period` bigint(20) NOT NULL DEFAULT 0 COMMENT '总课时(秒)',
 `del_flag` tinyint NOT NULL DEFAULT 0 COMMENT '删除标志(0为删除,1删除,默认0)',
 `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
 `create_by` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建人',
diff --git a/exam-admin/src/main/resources/db/migration/V20240531003_carousel.sql b/exam-admin/src/main/resources/db/migration/V20240531003_carousel.sql
index 674c517..c786da3 100644
--- a/exam-admin/src/main/resources/db/migration/V20240531003_carousel.sql
+++ b/exam-admin/src/main/resources/db/migration/V20240531003_carousel.sql
@@ -2,7 +2,6 @@
 -- ----------------------------
 -- 轮播图表
 -- ----------------------------
-drop table if exists `train_exam`.`sys_carousel`;
 CREATE TABLE `train_exam`.`sys_carousel`  (
 `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键' ,
 `status` tinyint NOT NULL DEFAULT 0 COMMENT '账号状态(0正常,1停用,默认0)',
diff --git a/exam-admin/src/main/resources/db/migration/V20240531004_category.sql b/exam-admin/src/main/resources/db/migration/V20240531004_category.sql
index d68395a..a41751c 100644
--- a/exam-admin/src/main/resources/db/migration/V20240531004_category.sql
+++ b/exam-admin/src/main/resources/db/migration/V20240531004_category.sql
@@ -2,12 +2,12 @@
 -- ----------------------------
 -- 课程分类表
 -- ----------------------------
-drop table if exists `train_exam`.`sys_category`;
 CREATE TABLE `train_exam`.`sys_category`  (
 `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键' ,
 `parent_id` bigint(20)  NOT NULL DEFAULT 0 COMMENT '父分类id',
 `name` varchar(30) NOT NULL COMMENT '分类名称',
 `category_type` tinyint  NOT NULL DEFAULT 1 COMMENT '类型(1课程,2资源)',
+`del_flag` tinyint NOT NULL DEFAULT 0 COMMENT '删除标志(0为删除,1删除,默认0)',
 `status` tinyint NOT NULL DEFAULT 0 COMMENT '账号状态(0正常,1停用,默认0)',
 `sort` int UNSIGNED NOT NULL DEFAULT 1 COMMENT '排序',
 `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
diff --git a/exam-admin/src/main/resources/db/migration/V20240531005_course.sql b/exam-admin/src/main/resources/db/migration/V20240531005_course.sql
index e54c7fa..3e57099 100644
--- a/exam-admin/src/main/resources/db/migration/V20240531005_course.sql
+++ b/exam-admin/src/main/resources/db/migration/V20240531005_course.sql
@@ -1,7 +1,6 @@
 -- ----------------------------
 -- 课程表
 -- ----------------------------
-drop table if exists `train_exam`.`ex_course`;
 CREATE TABLE `train_exam`.`ex_course`  (
 `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键' ,
 `status` tinyint NOT NULL DEFAULT 0 COMMENT '课程状态(0正常,1停用,默认0)',
@@ -10,10 +9,10 @@
 `name` varchar(50)  NOT NULL  COMMENT '课程名称',
 `logo` varchar(255) NOT NULL DEFAULT '' COMMENT '课程封面',
 `introduce` text NULL  COMMENT '课程简介',
-`state` tinyint NULL DEFAULT 1 COMMENT '审批状态(0创建,1待审核,2审批通过,3审批不通过  默认0)',
+`state` tinyint NULL DEFAULT 0 COMMENT '审批状态(0创建,1待审核,2审批通过,3审批不通过  默认0)',
+`message` varchar(50)  NULL  COMMENT '审批意见',
 `company_id` bigint(20) NULL COMMENT '提交公司id',
 `privatize` tinyint NOT NULL DEFAULT 0  COMMENT '课程公开私有属性(0私有,1公开  默认0)',
-`period` bigint(20) NOT NULL DEFAULT 0 COMMENT '课时(单位秒)',
 `del_flag` tinyint NULL DEFAULT 0 COMMENT '删除标志(0代表存在,2代表删除,默认0)',
 `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
 `create_by` varchar(50) NULL DEFAULT NULL COMMENT '创建人',
diff --git a/exam-admin/src/main/resources/db/migration/V20240531006_course_chapter.sql b/exam-admin/src/main/resources/db/migration/V20240531006_course_chapter.sql
index 7c83cfe..aba3154 100644
--- a/exam-admin/src/main/resources/db/migration/V20240531006_course_chapter.sql
+++ b/exam-admin/src/main/resources/db/migration/V20240531006_course_chapter.sql
@@ -1,7 +1,6 @@
 -- ----------------------------
 -- 课程章节表
 -- ----------------------------
-drop table if exists `train_exam`.`ex_course_chapter`;
 CREATE TABLE `train_exam`.`ex_course_chapter`  (
 `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键' ,
 `status` tinyint NOT NULL DEFAULT 0 COMMENT '账号状态(0正常,1停用,默认0)',
diff --git a/exam-admin/src/main/resources/db/migration/V20240531007_course_chapter_period.sql b/exam-admin/src/main/resources/db/migration/V20240531007_course_chapter_period.sql
index 5f0b7f0..038c6d9 100644
--- a/exam-admin/src/main/resources/db/migration/V20240531007_course_chapter_period.sql
+++ b/exam-admin/src/main/resources/db/migration/V20240531007_course_chapter_period.sql
@@ -1,7 +1,6 @@
 -- ----------------------------
 -- 课时信息表
 -- ----------------------------
-drop table if exists `train_exam`.`ex_course_chapter_period`;
 CREATE TABLE `train_exam`.`ex_course_chapter_period`  (
 `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键' ,
 `status` tinyint NOT NULL DEFAULT 0 COMMENT '账号状态(0正常,1停用,默认0)',
diff --git a/exam-admin/src/main/resources/db/migration/V20240531008_resource.sql b/exam-admin/src/main/resources/db/migration/V20240531008_resource.sql
index 6abfb7d..90e6c38 100644
--- a/exam-admin/src/main/resources/db/migration/V20240531008_resource.sql
+++ b/exam-admin/src/main/resources/db/migration/V20240531008_resource.sql
@@ -1,7 +1,6 @@
 -- ----------------------------
 -- 课程资源表
 -- ----------------------------
-drop table if exists `train_exam`.`ex_resource`;
 CREATE TABLE `train_exam`.`ex_resource`  (
 `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键' ,
 `status` tinyint NOT NULL DEFAULT 0 COMMENT '账号状态(0正常,1停用,默认0)',
@@ -13,9 +12,9 @@
 `company_id` bigint(20) NULL COMMENT '提交公司id',
 `resource_type` tinyint NOT NULL DEFAULT 1 COMMENT '资源种类(1:视频2:音频;3:文档,默认1)',
 `media_type` varchar(100)  NULL  COMMENT '资源类型',
-`resource_size` bigint(20) NOT NULL  COMMENT '资源大小',
+`resource_size` bigint(20) NOT NULL DEFAULT 0  COMMENT '资源大小',
 `resource_uri` varchar(200) NULL DEFAULT NULL  COMMENT '资源地址(存放第三方地址)',
-`resource_length` bigint(20) NULL DEFAULT NULL  COMMENT '资源时长(秒)',
+`resource_length` bigint(20) NULL DEFAULT 0  COMMENT '资源时长(秒)',
 `resource_path` varchar(120)  NULL DEFAULT NULL COMMENT '资源路径',
 `md5` varchar(50)  NOT NULL COMMENT '文件md5',
 `doc_page` int NULL DEFAULT 0 COMMENT '资源页数,单位页',
diff --git a/exam-admin/src/main/resources/db/migration/V20240531009_course_phase.sql b/exam-admin/src/main/resources/db/migration/V20240531009_course_phase.sql
index 9a5d837..8ecdb20 100644
--- a/exam-admin/src/main/resources/db/migration/V20240531009_course_phase.sql
+++ b/exam-admin/src/main/resources/db/migration/V20240531009_course_phase.sql
@@ -1,7 +1,6 @@
 -- ----------------------------
 -- 课时批次表
 -- ----------------------------
-drop table if exists `train_exam`.`ex_course_phase`;
 CREATE TABLE `train_exam`.`ex_course_phase`  (
 `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键' ,
 `code` varchar(12) NOT NULL COMMENT '批次编号',
diff --git a/exam-admin/src/main/resources/db/migration/V20240531010_student_study.sql b/exam-admin/src/main/resources/db/migration/V20240531010_student_study.sql
index 5dec065..8e8f1c3 100644
--- a/exam-admin/src/main/resources/db/migration/V20240531010_student_study.sql
+++ b/exam-admin/src/main/resources/db/migration/V20240531010_student_study.sql
@@ -1,7 +1,6 @@
 -- ----------------------------
 -- 课程学习学习日志表
 -- ----------------------------
-drop table if exists `train_exam`.`ex_student_study`;
 CREATE TABLE `train_exam`.`ex_student_study`  (
 `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键' ,
 `phase_id` bigint(20) NOT NULL COMMENT '课时批次id',
@@ -12,7 +11,6 @@
 `current_duration` bigint(20) NOT NULL DEFAULT 0 COMMENT '当前学习时长,单位秒',
 `current_page` int NOT NULL DEFAULT 0 COMMENT '当前学习页数,单位页',
 `progress` decimal(5, 2) NOT NULL DEFAULT 0 COMMENT '进度(百分比)',
-`resource_type` varchar(10) NOT NULL  COMMENT '资源类型(PPT,MP4,PDF)',
 `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
 `create_by` varchar(50) NULL DEFAULT NULL COMMENT '创建人',
 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
diff --git a/exam-admin/src/main/resources/db/migration/V20240531011_phase_student.sql b/exam-admin/src/main/resources/db/migration/V20240531011_phase_student.sql
index 47c2147..c33aa36 100644
--- a/exam-admin/src/main/resources/db/migration/V20240531011_phase_student.sql
+++ b/exam-admin/src/main/resources/db/migration/V20240531011_phase_student.sql
@@ -1,7 +1,6 @@
 -- ----------------------------
 -- 课时批次与学员关系表
 -- ----------------------------
-drop table if exists `train_exam`.`ex_phase_student`;
 CREATE TABLE `train_exam`.`ex_phase_student`  (
 `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键' ,
 `phase_id` bigint(20) NOT NULL COMMENT '课时批次id',
diff --git a/exam-admin/src/main/resources/db/migration/V20240531012_company_period.sql b/exam-admin/src/main/resources/db/migration/V20240531012_company_period.sql
index f941070..5d47ba5 100644
--- a/exam-admin/src/main/resources/db/migration/V20240531012_company_period.sql
+++ b/exam-admin/src/main/resources/db/migration/V20240531012_company_period.sql
@@ -1,14 +1,13 @@
 -- ----------------------------
 -- 公司课时变更记录表
 -- ----------------------------
-drop table if exists `train_exam`.`ex_company_period`;
 CREATE TABLE `train_exam`.`ex_company_period`  (
 `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键' ,
 `company_id` bigint NOT NULL COMMENT '公司id',
 `phase_id` bigint  NULL COMMENT '批次id',
 `origin` varchar(50) NOT NULL COMMENT '变动来源',
-`modify_period` int NOT NULL COMMENT '变动情况(增减课时)',
-`remain_period` int NOT NULL COMMENT '变动后剩余(分)',
+`modify_period` bigint(20) NOT NULL COMMENT '变动情况(增减课时)秒',
+`remain_period` bigint(20) NOT NULL COMMENT '变动后剩余(秒)',
 `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
 `create_by` varchar(50) NULL DEFAULT NULL COMMENT '创建人',
 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
diff --git a/exam-admin/src/main/resources/db/migration/V20240603001_exam_paper.sql b/exam-admin/src/main/resources/db/migration/V20240603001_exam_paper.sql
index 52e4bc9..f1576e4 100644
--- a/exam-admin/src/main/resources/db/migration/V20240603001_exam_paper.sql
+++ b/exam-admin/src/main/resources/db/migration/V20240603001_exam_paper.sql
@@ -1,7 +1,6 @@
 -- ----------------------------
 -- 考卷(组卷)表
 -- ----------------------------
-drop table if exists `train_exam`.`ex_exam_paper`;
 CREATE TABLE `train_exam`.`ex_exam_paper`  (
 `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键' ,
 `code` varchar(12) NOT NULL COMMENT '编号',
@@ -10,7 +9,7 @@
 `company_id` bigint NOT NULL COMMENT '公司id',
 `category_id` bigint(20) NOT NULL COMMENT '分类ID',
 `limit_time` int NOT NULL DEFAULT 0 COMMENT '考试限制时长',
-`limit` tinyint NOT NULL DEFAULT 0 COMMENT '是否现在考试时间(0否,1是,默认0)',
+`limited` tinyint NOT NULL DEFAULT 0 COMMENT '是否现在考试时间(0否,1是,默认0)',
 `single_num` int NOT NULL DEFAULT 0 COMMENT '单选题目数量',
 `single_score` int NOT NULL DEFAULT 0 COMMENT '单选题每题分数',
 `single_bank_id` bigint(20)  NULL COMMENT '单选题题库id',
@@ -25,6 +24,7 @@
 `judge_method` tinyint NOT NULL DEFAULT 1 COMMENT '出题方式1随机,2顺序,默认1',
 `pass_score` int NOT NULL DEFAULT 0 COMMENT '合格分数',
 `del_flag` tinyint NULL DEFAULT 0 COMMENT '删除标志(0代表存在,2代表删除,默认0)',
+`deadline` datetime NOT NULL  COMMENT '考试截止时间',
 `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
 `create_by` varchar(50) NULL DEFAULT NULL COMMENT '创建人',
 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
diff --git a/exam-admin/src/main/resources/db/migration/V20240603002_paper_student.sql b/exam-admin/src/main/resources/db/migration/V20240603002_paper_student.sql
index e675c29..c6f23b6 100644
--- a/exam-admin/src/main/resources/db/migration/V20240603002_paper_student.sql
+++ b/exam-admin/src/main/resources/db/migration/V20240603002_paper_student.sql
@@ -1,7 +1,6 @@
 -- ----------------------------
 -- 考卷与学员关系表
 -- ----------------------------
-drop table if exists `train_exam`.`ex_paper_student`;
 CREATE TABLE `train_exam`.`ex_paper_student`  (
 `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键' ,
 `paper_id` bigint(20) NOT NULL COMMENT '考卷id',
diff --git a/exam-admin/src/main/resources/db/migration/V20240603003_question.sql b/exam-admin/src/main/resources/db/migration/V20240603003_question.sql
index d8fc3ab..39b82f9 100644
--- a/exam-admin/src/main/resources/db/migration/V20240603003_question.sql
+++ b/exam-admin/src/main/resources/db/migration/V20240603003_question.sql
@@ -1,7 +1,6 @@
 -- ----------------------------
 -- 考题表
 -- ----------------------------
-drop table if exists `train_exam`.`ex_question`;
 CREATE TABLE `train_exam`.`ex_question`  (
 `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键' ,
 `question_type` tinyint NOT NULL DEFAULT 1 COMMENT '考题类型(1单选题,2多选题,3判断题 默认1)',
diff --git a/exam-admin/src/main/resources/db/migration/V20240603004_student_answer.sql b/exam-admin/src/main/resources/db/migration/V20240603004_student_answer.sql
index 895c9c9..554fecd 100644
--- a/exam-admin/src/main/resources/db/migration/V20240603004_student_answer.sql
+++ b/exam-admin/src/main/resources/db/migration/V20240603004_student_answer.sql
@@ -1,7 +1,6 @@
 -- ----------------------------
 -- 学员与考试题目关系表
 -- ----------------------------
-drop table if exists `train_exam`.`ex_student_answer`;
 CREATE TABLE `train_exam`.`ex_student_answer`  (
 `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键' ,
 `paper_id` bigint(20) NOT NULL COMMENT '考卷id',
diff --git a/exam-admin/src/main/resources/db/migration/V20240603005_paper_question.sql b/exam-admin/src/main/resources/db/migration/V20240603005_paper_question.sql
index e31bdbc..c2141f1 100644
--- a/exam-admin/src/main/resources/db/migration/V20240603005_paper_question.sql
+++ b/exam-admin/src/main/resources/db/migration/V20240603005_paper_question.sql
@@ -1,7 +1,6 @@
 -- ----------------------------
 -- 试卷与题目关系表
 -- ----------------------------
-drop table if exists `train_exam`.`ex_paper_question`;
 CREATE TABLE `train_exam`.`ex_paper_question`  (
 `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键' ,
 `paper_id` bigint(20) NOT NULL COMMENT '考卷id',
diff --git a/exam-admin/src/main/resources/db/migration/V20240604001_exam_record.sql b/exam-admin/src/main/resources/db/migration/V20240604001_exam_record.sql
index e4410e7..a3589e0 100644
--- a/exam-admin/src/main/resources/db/migration/V20240604001_exam_record.sql
+++ b/exam-admin/src/main/resources/db/migration/V20240604001_exam_record.sql
@@ -1,14 +1,13 @@
 -- ----------------------------
 -- 线下教育登记表
 -- ----------------------------
-drop table if exists `train_exam`.`ex_exam_record`;
 CREATE TABLE `train_exam`.`ex_exam_record`  (
 `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键' ,
 `company_id` bigint(20) NOT NULL COMMENT '公司id',
 `student_id` bigint(20) NOT NULL COMMENT '学员id',
 `plan_name` varchar(50) NOT NULL COMMENT '计划名称',
 `course_name` varchar(50) NOT NULL COMMENT '课程名称',
-`level` varchar(20) NOT NULL COMMENT '培训等级',
+`level` tinyint NOT NULL DEFAULT 1 COMMENT '培训等级(1公司级 2部门级 3车间级 默认1)',
 `period` int NOT NULL COMMENT '要求课时(分)',
 `actual_period` int NOT NULL COMMENT '实际课时(分)',
 `score` int NOT NULL COMMENT '考试成绩',
diff --git a/exam-admin/src/main/resources/db/migration/V20240614001_question_bank.sql b/exam-admin/src/main/resources/db/migration/V20240614001_question_bank.sql
index 85c8d88..282249a 100644
--- a/exam-admin/src/main/resources/db/migration/V20240614001_question_bank.sql
+++ b/exam-admin/src/main/resources/db/migration/V20240614001_question_bank.sql
@@ -1,11 +1,10 @@
 -- ----------------------------
 -- 题库表
 -- ----------------------------
-drop table if exists `train_exam`.`ex_question_bank`;
 CREATE TABLE `train_exam`.`ex_question_bank`  (
 `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键' ,
 `name` varchar(50) NOT NULL  COMMENT '题库名称',
-`company_id` bigint NOT NULL COMMENT '公司id',
+`company_id` bigint  NULL COMMENT '公司id',
 `category_id` bigint(20) NOT NULL COMMENT '分类ID',
 `del_flag` tinyint NULL DEFAULT 0 COMMENT '删除标志(0代表存在,2代表删除,默认0)',
 `privatize` tinyint NOT NULL DEFAULT 0  COMMENT '课程公开私有属性(0私有,1公开  默认0)',
diff --git a/exam-admin/src/main/resources/db/migration/V20240619001_exercise_answer.sql b/exam-admin/src/main/resources/db/migration/V20240619001_exercise_answer.sql
index a790c7f..72ce674 100644
--- a/exam-admin/src/main/resources/db/migration/V20240619001_exercise_answer.sql
+++ b/exam-admin/src/main/resources/db/migration/V20240619001_exercise_answer.sql
@@ -1,7 +1,6 @@
 -- ----------------------------
 -- 学员与练习题关系表
 -- ----------------------------
-drop table if exists `train_exam`.`ex_exercise_answer`;
 CREATE TABLE `train_exam`.`ex_exercise_answer`  (
 `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键' ,
 `bank_id` bigint(20) NOT NULL COMMENT '题库id',
@@ -16,5 +15,5 @@
 `remark` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注',
 `version` int NULL DEFAULT 0 COMMENT '乐观锁',
 PRIMARY KEY (`id`) USING BTREE,
-UNIQUE KEY `paper_student_id` (`student_id`,`question_id`)
+UNIQUE KEY `question_student_id` (`student_id`,`question_id`)
 ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '学员与练习题关系表' ROW_FORMAT = DYNAMIC;
diff --git a/exam-admin/src/main/resources/db/migration/V20240731001_change_question.sql b/exam-admin/src/main/resources/db/migration/V20240731001_change_question.sql
new file mode 100644
index 0000000..792fd92
--- /dev/null
+++ b/exam-admin/src/main/resources/db/migration/V20240731001_change_question.sql
@@ -0,0 +1,2 @@
+ALTER TABLE `train_exam`.`ex_question`
+MODIFY COLUMN `answer` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '答案';
\ No newline at end of file
diff --git a/exam-admin/src/main/resources/db/migration/V20240801001_change_paper_student.sql b/exam-admin/src/main/resources/db/migration/V20240801001_change_paper_student.sql
new file mode 100644
index 0000000..729cecd
--- /dev/null
+++ b/exam-admin/src/main/resources/db/migration/V20240801001_change_paper_student.sql
@@ -0,0 +1,2 @@
+ALTER TABLE `train_exam`.`ex_paper_student`
+ADD COLUMN `state` tinyint NOT NULL DEFAULT 0 COMMENT '状态:0待考试,1待批阅 2批阅完成';
\ No newline at end of file
diff --git a/exam-admin/src/main/resources/db/migration/V20240801002_change_exam_paper.sql b/exam-admin/src/main/resources/db/migration/V20240801002_change_exam_paper.sql
new file mode 100644
index 0000000..ca3a0be
--- /dev/null
+++ b/exam-admin/src/main/resources/db/migration/V20240801002_change_exam_paper.sql
@@ -0,0 +1,14 @@
+ALTER TABLE `train_exam`.`ex_exam_paper`
+MODIFY COLUMN `single_num` int NULL DEFAULT 0 COMMENT '单选题目数量',
+MODIFY COLUMN `single_score` int NULL DEFAULT 0 COMMENT '单选题每题分数',
+MODIFY COLUMN `single_method` tinyint NULL DEFAULT 1 COMMENT '出题方式1随机,2顺序,默认1',
+MODIFY COLUMN `multi_num` int NULL DEFAULT 0 COMMENT '多选题目数量',
+MODIFY COLUMN `multi_score` int NULL DEFAULT 0 COMMENT '多选题每题分数',
+MODIFY COLUMN `multi_method` tinyint NULL DEFAULT 1 COMMENT '出题方式1随机,2顺序,默认1',
+MODIFY COLUMN `judge_num` int NULL DEFAULT 0 COMMENT '判断题目数量',
+MODIFY COLUMN `judge_score` int NULL DEFAULT 0 COMMENT '判断题每题分数',
+MODIFY COLUMN `judge_method` tinyint NULL DEFAULT 1 COMMENT '出题方式1随机,2顺序,默认1',
+ADD COLUMN `easy_num` int NULL DEFAULT 0 COMMENT '简答题题目数量',
+ADD COLUMN `easy_score` int NULL DEFAULT 0 COMMENT '简答题每题分数',
+ADD COLUMN `easy_bank_id` bigint NULL COMMENT '简答题题库id',
+ADD COLUMN `easy_method` tinyint NULL DEFAULT 1 COMMENT '出题方式1随机,2顺序,默认1';
\ No newline at end of file
diff --git a/exam-admin/src/main/resources/db/migration/V20240801003_change_student_answer.sql b/exam-admin/src/main/resources/db/migration/V20240801003_change_student_answer.sql
new file mode 100644
index 0000000..1961aa3
--- /dev/null
+++ b/exam-admin/src/main/resources/db/migration/V20240801003_change_student_answer.sql
@@ -0,0 +1,3 @@
+ALTER TABLE `train_exam`.`ex_student_answer`
+MODIFY COLUMN `passed` tinyint NULL DEFAULT NULL COMMENT '是否正确(0错误,1正确,2待批改)',
+ADD COLUMN `score` int NULL COMMENT '得分';
\ No newline at end of file
diff --git a/exam-admin/src/main/resources/db/migration/V20240802001_change_student_answer.sql b/exam-admin/src/main/resources/db/migration/V20240802001_change_student_answer.sql
new file mode 100644
index 0000000..671e9ad
--- /dev/null
+++ b/exam-admin/src/main/resources/db/migration/V20240802001_change_student_answer.sql
@@ -0,0 +1,5 @@
+ALTER TABLE `train_exam`.`ex_student_answer`
+MODIFY COLUMN `answer` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '答案';
+
+ALTER TABLE `train_exam`.`ex_exercise_answer`
+MODIFY COLUMN `answer` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci  NULL COMMENT '答案';
\ No newline at end of file
diff --git a/exam-admin/src/main/resources/db/migration/V20240828001_change_question.sql b/exam-admin/src/main/resources/db/migration/V20240828001_change_question.sql
new file mode 100644
index 0000000..1e50bd4
--- /dev/null
+++ b/exam-admin/src/main/resources/db/migration/V20240828001_change_question.sql
@@ -0,0 +1,2 @@
+ALTER TABLE `train_exam`.`ex_question`
+MODIFY COLUMN `company_id` bigint NULL COMMENT '公司id' AFTER `bank_id`;
\ No newline at end of file
diff --git a/exam-admin/src/main/resources/logback-spring.xml b/exam-admin/src/main/resources/logback-spring.xml
new file mode 100644
index 0000000..4b3a77f
--- /dev/null
+++ b/exam-admin/src/main/resources/logback-spring.xml
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE configuration>
+<configuration>
+    <!--引用默认日志配置-->
+    <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
+    <!--使用默认的控制台日志输出实现-->
+    <include resource="org/springframework/boot/logging/logback/console-appender.xml"/>
+    <!--应用名称-->
+    <springProperty scope="context" name="APP_NAME" source="spring.application.name" defaultValue="springBoot"/>
+    <!-- 日志输出格式 -->
+    <property name="log.pattern"
+              value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%X{requestId}] [%X{clientIP}] [%X{userId}] - [%C,%M,%L] - %msg%n"/>
+
+    <property name="log.path" value="logs"/>
+    <!--日志文件保存路径-->
+    <property name="LOG_FILE_PATH" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}}/logs}"/>
+
+
+
+    <!-- 控制台输出 -->
+    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <pattern>${log.pattern}</pattern>
+            <charset>utf8</charset>
+        </encoder>
+    </appender>
+
+    <!-- 系统日志输出 -->
+    <appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <!--        <file>${log.path}/zero-spring-info.log</file>-->
+        <!-- 循环政策:基于时间创建日志文件 -->
+        <!--        <file>-->
+        <!--            logs/zero-spring.log-->
+        <!--        </file>-->
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <!-- 日志文件名格式 -->
+            <fileNamePattern>${log.path}/${APP_NAME}-info-%d{yyyy-MM-dd}-%i.log</fileNamePattern>
+            <totalSizeCap>30GB</totalSizeCap>
+            <!--设置日志文件大小,超过就重新生成文件,默认50M-->
+            <maxFileSize>100MB</maxFileSize>
+            <!-- 日志最大的历史 30天 -->
+            <maxHistory>30</maxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <!-- 过滤的级别 -->
+            <level>INFO</level>
+            <!-- 匹配时的操作:接收(记录) -->
+            <onMatch>ACCEPT</onMatch>
+            <!-- 不匹配时的操作:拒绝(不记录) -->
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <!--        <file>${log.path}/zero-spring-error.log</file>-->
+        <!-- 循环政策:基于时间创建日志文件 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <!-- 日志文件名格式 -->
+            <fileNamePattern>${log.path}/${APP_NAME}-error-%d{yyyy-MM-dd}-%i.log</fileNamePattern>
+            <totalSizeCap>10GB</totalSizeCap>
+            <!--设置日志文件大小,超过就重新生成文件,默认50M-->
+            <maxFileSize>100MB</maxFileSize>
+            <!-- 日志最大的历史 30天 -->
+            <maxHistory>30</maxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <!-- 过滤的级别 -->
+            <level>ERROR</level>
+            <!-- 匹配时的操作:接收(记录) -->
+            <onMatch>ACCEPT</onMatch>
+            <!-- 不匹配时的操作:拒绝(不记录) -->
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+
+    <!--控制框架输出日志-->
+    <logger name="org.slf4j" level="INFO"/>
+    <logger name="springfox" level="INFO"/>
+    <logger name="io.swagger" level="INFO"/>
+    <logger name="org.springframework" level="INFO"/>
+    <logger name="org.hibernate.validator" level="INFO"/>
+
+    <root level="INFO">
+<!--        <appender-ref ref="console"/>-->
+        <appender-ref ref="file_info"/>
+        <appender-ref ref="file_error"/>
+    </root>
+
+
+    <root level="DEBUG">
+        <appender-ref ref="console"/>
+    </root>
+</configuration>
diff --git a/exam-admin/src/test/java/com/gkhy/exam/admin/ExcelTest.java b/exam-admin/src/test/java/com/gkhy/exam/admin/ExcelTest.java
new file mode 100644
index 0000000..48611ef
--- /dev/null
+++ b/exam-admin/src/test/java/com/gkhy/exam/admin/ExcelTest.java
@@ -0,0 +1,24 @@
+package com.gkhy.exam.admin;
+
+import com.gkhy.exam.system.service.SysCommonService;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.jupiter.api.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = GkhyAdminApplication.class)
+@ActiveProfiles("dev")
+@Slf4j
+public class ExcelTest {
+    @Autowired
+    private SysCommonService commonService;
+
+    @Test
+    public void importTest(){
+        commonService.importStudent();
+    }
+}
diff --git a/exam-admin/src/test/java/com/gkhy/exam/admin/JobTest.java b/exam-admin/src/test/java/com/gkhy/exam/admin/JobTest.java
new file mode 100644
index 0000000..326afdc
--- /dev/null
+++ b/exam-admin/src/test/java/com/gkhy/exam/admin/JobTest.java
@@ -0,0 +1,27 @@
+package com.gkhy.exam.admin;
+
+import com.gkhy.exam.framework.job.PaperStudentJob;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = GkhyAdminApplication.class)
+@ActiveProfiles("dev")
+@Slf4j
+public class JobTest {
+    @Autowired
+    private PaperStudentJob paperStudentJob;
+
+
+    @Test
+    public void jobTest(){
+        paperStudentJob.doprogress();
+    }
+
+
+}
diff --git a/exam-admin/src/test/java/com/gkhy/exam/admin/PasswordTest.java b/exam-admin/src/test/java/com/gkhy/exam/admin/PasswordTest.java
index 2767e4e..4d01446 100644
--- a/exam-admin/src/test/java/com/gkhy/exam/admin/PasswordTest.java
+++ b/exam-admin/src/test/java/com/gkhy/exam/admin/PasswordTest.java
@@ -12,6 +12,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Optional;
 import java.util.Random;
 
 @RunWith(SpringRunner.class)
@@ -65,4 +66,15 @@
         b.add("c");
         return aa;
     }
+
+    @Test
+    public void testNum(){
+        Integer a=null;
+        int b=0;
+        if(Optional.ofNullable(a).orElse(0)>b){
+            System.out.println("gggggg");
+        }else{
+            System.out.println("hhhhhh");
+        }
+    }
 }
diff --git a/exam-admin/src/test/java/com/gkhy/exam/admin/QuestionTest.java b/exam-admin/src/test/java/com/gkhy/exam/admin/QuestionTest.java
new file mode 100644
index 0000000..1cd8ca6
--- /dev/null
+++ b/exam-admin/src/test/java/com/gkhy/exam/admin/QuestionTest.java
@@ -0,0 +1,198 @@
+package com.gkhy.exam.admin;
+
+import com.alibaba.fastjson2.JSONArray;
+import com.alibaba.fastjson2.JSONObject;
+import com.gkhy.exam.system.domain.ExQuestion;
+import com.gkhy.exam.system.service.ExQuestionService;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = GkhyAdminApplication.class)
+@ActiveProfiles("dev")
+@Slf4j
+public class QuestionTest {
+    @Autowired
+    private ExQuestionService questionService;
+
+    // 定义选项数量
+    private static final int OPTION_COUNT = 4;
+    // 随机生成器
+    private static final Random random = new Random();
+
+    @Test
+    public void questionData(){
+        List<ExQuestion>questions=new ArrayList<>();
+        for(int i=0;i<300;i++){
+            ExQuestion question=generateSingleQuestion();
+            questions.add(question);
+            question=generateMultiQuestion();
+            questions.add(question);
+            question=generateJudgeQuestion();
+            questions.add(question);
+            if(questions.size()>100){
+                questionService.saveBatch(questions);
+                questions.clear();
+            }
+        }
+        if(questions.size()>0){
+            questionService.saveBatch(questions);
+            questions.clear();
+        }
+//        ExQuestion question=generateSingleQuestion();
+//        System.out.println(question);
+//        question=generateMultiQuestion();
+//        System.out.println(question);
+//        question=generateJudgeQuestion();
+//        System.out.println(question);
+    }
+
+    // 生成单选题目
+    public  ExQuestion generateSingleQuestion() {
+        int a=random.nextInt(1000);
+        int b=random.nextInt(1000);
+        int sum=a+b;
+        List<String> options=new ArrayList<>();
+        options.add("A");
+        options.add("B");
+        options.add("C");
+        options.add("D");
+        int index=random.nextInt(4);
+        String title="算术运算题,整数"+a+"与整数"+b+"之和,等于多少?";
+        JSONObject object=new JSONObject();
+        object.put("analyze","无");
+        JSONArray jsonArray=new JSONArray();
+        for(int i=0;i<4;i++){
+            if(i==index){
+                JSONObject itemObject=new JSONObject();
+                itemObject.put("prefix",options.get(index));
+                itemObject.put("content",sum);
+                jsonArray.add(itemObject);
+            }else{
+                JSONObject itemObject=new JSONObject();
+                itemObject.put("prefix",options.get(i));
+                itemObject.put("content",randomInt(sum));
+                jsonArray.add(itemObject);
+            }
+        }
+        object.put("items",jsonArray);
+        ExQuestion question=new ExQuestion();
+        question.setQuestionType(1);
+        question.setBankId(16L);
+        question.setCompanyId(21L);
+        question.setAnswer(options.get(index));
+        question.setTitle(title);
+        question.setPrivatize(0);
+        question.setContent(JSONObject.toJSONString(object));
+        return question;
+    }
+
+    // 生成多选题目
+    public  ExQuestion generateMultiQuestion() {
+        int a=random.nextInt(1000);
+        int b=random.nextInt(1000);
+        int sum=a+b;
+        List<String> options=new ArrayList<>();
+        options.add("A");
+        options.add("B");
+        options.add("C");
+        options.add("D");
+        options.add("E");
+        int indexa=random.nextInt(5);
+        int indexb=random.nextInt(5);
+        String title="算术运算题,整数"+a+"与整数"+b+"之和,等于多少?";
+        JSONObject object=new JSONObject();
+        object.put("analyze","无");
+        JSONArray jsonArray=new JSONArray();
+        for(int i=0;i<5;i++){
+            if(i==indexa){
+                JSONObject itemObject=new JSONObject();
+                itemObject.put("prefix",options.get(indexa));
+                itemObject.put("content",sum);
+                jsonArray.add(itemObject);
+            }else if(i==indexb) {
+                JSONObject itemObject=new JSONObject();
+                itemObject.put("prefix",options.get(indexb));
+                itemObject.put("content",sum);
+                jsonArray.add(itemObject);
+            }else{
+                JSONObject itemObject=new JSONObject();
+                itemObject.put("prefix",options.get(i));
+                itemObject.put("content",randomInt(sum));
+                jsonArray.add(itemObject);
+            }
+        }
+        object.put("items",jsonArray);
+        ExQuestion question=new ExQuestion();
+        question.setQuestionType(2);
+        question.setBankId(16L);
+        question.setCompanyId(21L);
+        String answer="";
+        if(indexa==indexb){
+            answer=options.get(indexa);
+        }else{
+            if(indexa>indexb){
+                answer=options.get(indexb)+","+options.get(indexa);
+            }else{
+                answer=options.get(indexa)+","+options.get(indexb);
+            }
+        }
+        question.setAnswer(answer);
+        question.setTitle(title);
+        question.setPrivatize(0);
+        question.setContent(JSONObject.toJSONString(object));
+        return question;
+    }
+
+    // 生成判断题目
+    public  ExQuestion generateJudgeQuestion() {
+        int a=random.nextInt(1000);
+        int b=random.nextInt(1000);
+        int sum=a+b;
+        List<String> options=new ArrayList<>();
+        options.add("A");
+        options.add("B");
+        int index=random.nextInt(2);
+        String title="算术运算题,整数"+a+"与整数"+b+"之和,等于="+(index==0?sum:randomInt(sum));
+        JSONObject object=new JSONObject();
+        object.put("analyze","无");
+        JSONArray jsonArray=new JSONArray();
+        JSONObject itemObject=new JSONObject();
+        itemObject.put("prefix",options.get(0));
+        itemObject.put("content","是");
+        jsonArray.add(itemObject);
+        itemObject=new JSONObject();
+        itemObject.put("prefix",options.get(1));
+        itemObject.put("content","否");
+        jsonArray.add(itemObject);
+        object.put("items",jsonArray);
+        ExQuestion question=new ExQuestion();
+        question.setQuestionType(3);
+        question.setBankId(16L);
+        question.setCompanyId(21L);
+        question.setAnswer(index==0?options.get(0):options.get(1));
+        question.setTitle(title);
+        question.setPrivatize(0);
+        question.setContent(JSONObject.toJSONString(object));
+        return question;
+    }
+
+    public String randomInt(int answer){
+        int a=random.nextInt(2000);
+        while (a==answer) {
+            a = random.nextInt(2000);
+        }
+        return a+"";
+    }
+
+
+}
diff --git a/exam-common/pom.xml b/exam-common/pom.xml
index 42c7b96..36da6f1 100644
--- a/exam-common/pom.xml
+++ b/exam-common/pom.xml
@@ -104,6 +104,14 @@
             <artifactId>fastjson2</artifactId>
         </dependency>
         <dependency>
+            <groupId>com.alibaba.fastjson2</groupId>
+            <artifactId>fastjson2-extension</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.fastjson2</groupId>
+            <artifactId>fastjson2-extension-spring5</artifactId>
+        </dependency>
+        <dependency>
             <groupId>com.github.ben-manes.caffeine</groupId>
             <artifactId>caffeine</artifactId>
         </dependency>
@@ -139,6 +147,11 @@
             <artifactId>jaudiotagger</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>easyexcel</artifactId>
+        </dependency>
+
     </dependencies>
 
 </project>
\ No newline at end of file
diff --git a/exam-common/src/main/java/com/gkhy/exam/common/annotation/DataDesensitization.java b/exam-common/src/main/java/com/gkhy/exam/common/annotation/DataDesensitization.java
new file mode 100644
index 0000000..1de576b
--- /dev/null
+++ b/exam-common/src/main/java/com/gkhy/exam/common/annotation/DataDesensitization.java
@@ -0,0 +1,13 @@
+package com.gkhy.exam.common.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * 数据脱敏注解,方法含有该注解表示需要数据脱敏
+ */
+@Target({ElementType.PARAMETER,ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface DataDesensitization {
+
+}
diff --git a/exam-common/src/main/java/com/gkhy/exam/common/annotation/DataDesensitizationType.java b/exam-common/src/main/java/com/gkhy/exam/common/annotation/DataDesensitizationType.java
new file mode 100644
index 0000000..1003dba
--- /dev/null
+++ b/exam-common/src/main/java/com/gkhy/exam/common/annotation/DataDesensitizationType.java
@@ -0,0 +1,19 @@
+package com.gkhy.exam.common.annotation;
+
+import com.gkhy.exam.common.enums.SensitiveTypeEnum;
+
+import java.lang.annotation.*;
+
+/**
+ * 数据脱敏注解,字段上含有该注解表示需要数据脱敏
+ */
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface DataDesensitizationType {
+    /**
+     * 脱敏类型(规则)
+     * @return
+     */
+    SensitiveTypeEnum type();
+}
diff --git a/exam-common/src/main/java/com/gkhy/exam/common/config/FFmpegConfig.java b/exam-common/src/main/java/com/gkhy/exam/common/config/FFmpegConfig.java
index 7e16065..0eecf2d 100644
--- a/exam-common/src/main/java/com/gkhy/exam/common/config/FFmpegConfig.java
+++ b/exam-common/src/main/java/com/gkhy/exam/common/config/FFmpegConfig.java
@@ -20,8 +20,11 @@
     @Bean
     public FFmpeg fFmpeg() {
         String path = System.getProperty("user.dir");
+        if(path.endsWith("exam-admin")){
+            path=path.replace("\\exam-admin","");
+        }
         if (isLinux()){
-            path+="ffmpeg/ffmpeg-linux/ffmpeg";
+            path+="/ffmpeg/ffmpeg-linux/ffmpeg";
         }else if (isWindows()){
             path+="/ffmpeg/ffmpeg-win/bin/ffmpeg.exe";
         }
@@ -34,7 +37,7 @@
     public FFprobe fFprobe() {
         String path = System.getProperty("user.dir");
         if (isLinux()){
-            path+="ffmpeg/ffmpeg-linux/ffprobe";
+            path+="/ffmpeg/ffmpeg-linux/ffprobe";
         }else if (isWindows()){
             path+="/ffmpeg/ffmpeg-win/bin/ffprobe.exe";
         }
diff --git a/exam-common/src/main/java/com/gkhy/exam/common/constant/Constant.java b/exam-common/src/main/java/com/gkhy/exam/common/constant/Constant.java
index 3e91adb..345db8e 100644
--- a/exam-common/src/main/java/com/gkhy/exam/common/constant/Constant.java
+++ b/exam-common/src/main/java/com/gkhy/exam/common/constant/Constant.java
@@ -142,4 +142,14 @@
      */
     public static final String[] JOB_ERROR_STR = { "java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml",
             "org.springframework", "org.apache", "com.ruoyi.common.utils.file", "com.ruoyi.common.config" };
+
+
+    /**
+     * 考试通过
+     */
+    public static final Integer EXAM_PASS = 1;
+    /**
+     * 考试未通过
+     */
+    public static final Integer EXAM_UNPASS = 0;
 }
diff --git a/exam-common/src/main/java/com/gkhy/exam/common/domain/TableSupport.java b/exam-common/src/main/java/com/gkhy/exam/common/domain/TableSupport.java
index 6b03572..c630774 100644
--- a/exam-common/src/main/java/com/gkhy/exam/common/domain/TableSupport.java
+++ b/exam-common/src/main/java/com/gkhy/exam/common/domain/TableSupport.java
@@ -42,7 +42,11 @@
     {
         PageDomain pageDomain = new PageDomain();
         pageDomain.setPageNum(Convert.toInt(ServletUtils.getParameter(PAGE_NUM), 1));
-        pageDomain.setPageSize(Convert.toInt(ServletUtils.getParameter(PAGE_SIZE), 10));
+        Integer pageSize=Convert.toInt(ServletUtils.getParameter(PAGE_SIZE), 10);
+        if(pageSize>100){
+            pageSize=100;
+        }
+        pageDomain.setPageSize(pageSize);
         pageDomain.setOrderByColumn(ServletUtils.getParameter(ORDER_BY_COLUMN));
         pageDomain.setIsAsc(ServletUtils.getParameter(IS_ASC));
         pageDomain.setReasonable(ServletUtils.getParameterToBool(REASONABLE));
diff --git a/exam-common/src/main/java/com/gkhy/exam/common/domain/entity/SysUser.java b/exam-common/src/main/java/com/gkhy/exam/common/domain/entity/SysUser.java
index da4d52a..39eb122 100644
--- a/exam-common/src/main/java/com/gkhy/exam/common/domain/entity/SysUser.java
+++ b/exam-common/src/main/java/com/gkhy/exam/common/domain/entity/SysUser.java
@@ -39,6 +39,7 @@
     private Long id;
 
     @NotBlank(message = "登录账号不能为空")
+    @Length(min = 2,  message = "登录账号长度不正确")
     @ApiModelProperty(value = "登录账号",required = true)
     @TableField("username")
     private String username;
@@ -73,6 +74,7 @@
     private Long companyId;
 
     @NotBlank(message = "密码不能为空")
+    @Length(min = 2,  message = "密码长度不正确")
     @ApiModelProperty(value = "密码",required = true)
     @TableField("password")
     private String password;
@@ -106,8 +108,13 @@
     @TableField(exist = false)
     private String companyName;
 
+    @ApiModelProperty("剩余课时(分)")
+    @TableField(exist = false)
+    private Long remainPeriod;
+
     @ApiModelProperty("父级账号名称")
     @TableField(exist = false)
     private String parentName;
 
+
 }
diff --git a/exam-common/src/main/java/com/gkhy/exam/common/enums/PaperStudentStateEnum.java b/exam-common/src/main/java/com/gkhy/exam/common/enums/PaperStudentStateEnum.java
new file mode 100644
index 0000000..60b8ed0
--- /dev/null
+++ b/exam-common/src/main/java/com/gkhy/exam/common/enums/PaperStudentStateEnum.java
@@ -0,0 +1,29 @@
+package com.gkhy.exam.common.enums;
+
+/**
+ * 考试试卷状态
+ */
+public enum PaperStudentStateEnum {
+    WAIT_EXAM(0, "待考试"),
+    WAIT_REVIEW(1, "待批改"),
+    DONE_REVIEW(2, "批改完成");
+
+    private final Integer code;
+    private final String info;
+
+    PaperStudentStateEnum(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/enums/QuestionTypeEnum.java b/exam-common/src/main/java/com/gkhy/exam/common/enums/QuestionTypeEnum.java
index 682cff2..b0e411a 100644
--- a/exam-common/src/main/java/com/gkhy/exam/common/enums/QuestionTypeEnum.java
+++ b/exam-common/src/main/java/com/gkhy/exam/common/enums/QuestionTypeEnum.java
@@ -6,7 +6,8 @@
 public enum QuestionTypeEnum {
     SINGLE(1, "单选题"),
     MULTI(2, "多选题"),
-    JUDGE(3, "判断题");
+    JUDGE(3, "判断题"),
+    EASY(4, "简答题");
 
     private final Integer code;
     private final String info;
diff --git a/exam-common/src/main/java/com/gkhy/exam/common/enums/SensitiveTypeEnum.java b/exam-common/src/main/java/com/gkhy/exam/common/enums/SensitiveTypeEnum.java
new file mode 100644
index 0000000..a0867d3
--- /dev/null
+++ b/exam-common/src/main/java/com/gkhy/exam/common/enums/SensitiveTypeEnum.java
@@ -0,0 +1,10 @@
+package com.gkhy.exam.common.enums;
+
+/**
+ * 脱敏类型枚举
+ */
+public enum SensitiveTypeEnum {
+    CHINESE_NAME,
+    ID_CARD,
+    MOBILE_PHONE;
+}
diff --git a/exam-common/src/main/java/com/gkhy/exam/common/enums/StudentAnswerPassEnum.java b/exam-common/src/main/java/com/gkhy/exam/common/enums/StudentAnswerPassEnum.java
new file mode 100644
index 0000000..bf3e5a3
--- /dev/null
+++ b/exam-common/src/main/java/com/gkhy/exam/common/enums/StudentAnswerPassEnum.java
@@ -0,0 +1,29 @@
+package com.gkhy.exam.common.enums;
+
+/**
+ * 考试试卷状态
+ */
+public enum StudentAnswerPassEnum {
+    ERROR(0, "错误"),
+    CORRECT(1, "正确"),
+    WAIT_REVIEW(2, "待批改");
+
+    private final Integer code;
+    private final String info;
+
+    StudentAnswerPassEnum(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/excel/StudentExcelData.java b/exam-common/src/main/java/com/gkhy/exam/common/excel/StudentExcelData.java
new file mode 100644
index 0000000..6e51f8b
--- /dev/null
+++ b/exam-common/src/main/java/com/gkhy/exam/common/excel/StudentExcelData.java
@@ -0,0 +1,51 @@
+package com.gkhy.exam.common.excel;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class StudentExcelData {
+    @ExcelProperty("用户序号")
+    private String index;
+    @ExcelProperty("公司名称")
+    private String companyName;
+
+    @ExcelProperty("姓名")
+    private String name;
+
+    @ExcelProperty("用户性别")
+    private String sex;
+
+    @ExcelProperty("身份证号")
+    private String idNo;
+
+    @ExcelProperty("手机号码")
+    private String phone;
+
+    @ExcelProperty("密码")
+    private String password;
+
+    @ExcelProperty("部门名称")
+    private String deptName;
+
+    @ExcelProperty("是否是部门级账号")
+    private String isDept;
+
+    @ExcelProperty("车间名称")
+    private String workShopName;
+
+    @ExcelProperty("是否是车间级账号")
+    private String isWork;
+
+    @ExcelProperty("岗位")
+    private String post;
+
+    @ExcelProperty("职务")
+    private String duty;
+
+    @ExcelProperty("备注")
+    private String remark;
+
+}
diff --git a/exam-common/src/main/java/com/gkhy/exam/common/excel/StudentExcelDataListener.java b/exam-common/src/main/java/com/gkhy/exam/common/excel/StudentExcelDataListener.java
new file mode 100644
index 0000000..7b6b09e
--- /dev/null
+++ b/exam-common/src/main/java/com/gkhy/exam/common/excel/StudentExcelDataListener.java
@@ -0,0 +1,17 @@
+package com.gkhy.exam.common.excel;
+
+import com.alibaba.excel.context.AnalysisContext;
+import com.alibaba.excel.event.AnalysisEventListener;
+
+public class StudentExcelDataListener extends AnalysisEventListener<StudentExcelData> {
+    @Override
+    public void invoke(StudentExcelData studentExcelData, AnalysisContext analysisContext) {
+        System.out.println(studentExcelData);
+    }
+
+    @Override
+    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
+        //所有数据解析完成后的操作
+        System.out.println("doAfterAllAnalysed");
+    }
+}
diff --git a/exam-common/src/main/java/com/gkhy/exam/common/filter/XssFilter.java b/exam-common/src/main/java/com/gkhy/exam/common/filter/XssFilter.java
new file mode 100644
index 0000000..4244c2f
--- /dev/null
+++ b/exam-common/src/main/java/com/gkhy/exam/common/filter/XssFilter.java
@@ -0,0 +1,70 @@
+package com.gkhy.exam.common.filter;
+
+import com.gkhy.exam.common.utils.StringUtils;
+import org.springframework.http.HttpMethod;
+
+import javax.servlet.*;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 防止XSS攻击的过滤器
+ *
+ */
+public class XssFilter implements Filter
+{
+    /**
+     * 排除链接
+     */
+    public List<String> excludes = new ArrayList<>();
+
+    @Override
+    public void init(FilterConfig filterConfig) throws ServletException
+    {
+        String tempExcludes = filterConfig.getInitParameter("excludes");
+        if (StringUtils.isNotBlank(tempExcludes))
+        {
+            String[] url = tempExcludes.split(",");
+            for (int i = 0; url != null && i < url.length; i++)
+            {
+                excludes.add(url[i]);
+            }
+        }
+    }
+
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+            throws IOException, ServletException
+    {
+        HttpServletRequest req = (HttpServletRequest) request;
+        HttpServletResponse resp = (HttpServletResponse) response;
+        if (handleExcludeURL(req, resp))
+        {
+            chain.doFilter(request, response);
+            return;
+        }
+        XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request);
+        chain.doFilter(xssRequest, response);
+    }
+
+    private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response)
+    {
+        String url = request.getServletPath();
+        String method = request.getMethod();
+        // GET DELETE 不过滤
+        if (method == null || HttpMethod.GET.matches(method) || HttpMethod.DELETE.matches(method))
+        {
+            return true;
+        }
+        return StringUtils.matches(url, excludes);
+    }
+
+    @Override
+    public void destroy()
+    {
+
+    }
+}
\ No newline at end of file
diff --git a/exam-common/src/main/java/com/gkhy/exam/common/filter/XssHttpServletRequestWrapper.java b/exam-common/src/main/java/com/gkhy/exam/common/filter/XssHttpServletRequestWrapper.java
new file mode 100644
index 0000000..0e5b77b
--- /dev/null
+++ b/exam-common/src/main/java/com/gkhy/exam/common/filter/XssHttpServletRequestWrapper.java
@@ -0,0 +1,111 @@
+package com.gkhy.exam.common.filter;
+
+import com.gkhy.exam.common.utils.StringUtils;
+import com.gkhy.exam.common.utils.html.EscapeUtil;
+import org.apache.commons.io.IOUtils;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+
+import javax.servlet.ReadListener;
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+/**
+ * XSS过滤处理
+ *
+ */
+public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper
+{
+    /**
+     * @param request
+     */
+    public XssHttpServletRequestWrapper(HttpServletRequest request)
+    {
+        super(request);
+    }
+
+    @Override
+    public String[] getParameterValues(String name)
+    {
+        String[] values = super.getParameterValues(name);
+        if (values != null)
+        {
+            int length = values.length;
+            String[] escapesValues = new String[length];
+            for (int i = 0; i < length; i++)
+            {
+                // 防xss攻击和过滤前后空格
+                escapesValues[i] = EscapeUtil.clean(values[i]).trim();
+            }
+            return escapesValues;
+        }
+        return super.getParameterValues(name);
+    }
+
+    @Override
+    public ServletInputStream getInputStream() throws IOException
+    {
+        // 非json类型,直接返回
+        if (!isJsonRequest())
+        {
+            return super.getInputStream();
+        }
+
+        // 为空,直接返回
+        String json = IOUtils.toString(super.getInputStream(), "utf-8");
+        if (StringUtils.isBlank(json))
+        {
+            return super.getInputStream();
+        }
+
+        // xss过滤
+        json = EscapeUtil.clean(json).trim();
+        byte[] jsonBytes = json.getBytes("utf-8");
+        final ByteArrayInputStream bis = new ByteArrayInputStream(jsonBytes);
+        return new ServletInputStream()
+        {
+            @Override
+            public boolean isFinished()
+            {
+                return true;
+            }
+
+            @Override
+            public boolean isReady()
+            {
+                return true;
+            }
+
+            @Override
+            public int available() throws IOException
+            {
+                return jsonBytes.length;
+            }
+
+            @Override
+            public void setReadListener(ReadListener readListener)
+            {
+            }
+
+            @Override
+            public int read() throws IOException
+            {
+                return bis.read();
+            }
+        };
+    }
+
+    /**
+     * 是否是Json请求
+     * 
+     * @param request
+     */
+    public boolean isJsonRequest()
+    {
+        String header = super.getHeader(HttpHeaders.CONTENT_TYPE);
+        return StringUtils.startWithIgnoreCase(header, MediaType.APPLICATION_JSON_VALUE);
+    }
+}
\ No newline at end of file
diff --git a/exam-common/src/main/java/com/gkhy/exam/common/utils/DesenseUtil.java b/exam-common/src/main/java/com/gkhy/exam/common/utils/DesenseUtil.java
new file mode 100644
index 0000000..49ea2ab
--- /dev/null
+++ b/exam-common/src/main/java/com/gkhy/exam/common/utils/DesenseUtil.java
@@ -0,0 +1,78 @@
+package com.gkhy.exam.common.utils;
+
+import cn.hutool.core.util.DesensitizedUtil;
+import com.gkhy.exam.common.annotation.DataDesensitizationType;
+import com.gkhy.exam.common.api.CommonPage;
+import com.gkhy.exam.common.api.CommonResult;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.util.List;
+
+/**
+ * 脱密工具类,(缺陷,不支持子类数据脱密)
+ */
+public class DesenseUtil {
+
+    public static void assertResult(Object data) throws ClassNotFoundException, IllegalAccessException {
+        if(data instanceof CommonResult){
+            CommonResult cr= (CommonResult) data;
+            Object obj=cr.getData();
+            if(obj instanceof CommonPage){
+                assetListResult(((CommonPage)obj).getList());
+            }else if (obj instanceof List){
+                assetListResult(obj);
+            }else{
+                assetOneResult(obj);
+            }
+        }
+    }
+    public static void assetListResult(Object data) throws ClassNotFoundException, IllegalAccessException {
+        List list=(List) data;
+        for (Object record : list) {
+            Class<?> targetClass = Class.forName(record.getClass().getName());
+            Field[] fields = targetClass.getDeclaredFields();
+            reflexUpdateData(record, fields);
+        }
+    }
+
+    public static void assetOneResult(Object data) throws IllegalAccessException, ClassNotFoundException {
+        Class<?> targetClass = Class.forName(data.getClass().getName());
+        Field[] fields=targetClass.getDeclaredFields();
+        reflexUpdateData(data,fields);
+    }
+
+    public static void reflexUpdateData(Object data, Field[] fields) throws IllegalAccessException {
+        for (Field field : fields) {
+            field.setAccessible(true);
+            Object value = field.get(data);
+            if (!(value instanceof String)) {
+                continue;
+            }
+            String valueStr = (String) value;
+            Annotation[] annotations = field.getDeclaredAnnotations();
+            for (Annotation annotation : annotations) {
+                if (annotation instanceof DataDesensitizationType) {
+                    DataDesensitizationType targetAnnotation = (DataDesensitizationType) annotation;
+                    switch (targetAnnotation.type()) {
+                        case CHINESE_NAME: {
+                            field.set(data, DesensitizedUtil.chineseName(valueStr));
+                            break;
+                        }
+                        case ID_CARD: {
+                            field.set(data, DesensitizedUtil.idCardNum(valueStr, 3, 3));
+                            break;
+                        }
+                        case MOBILE_PHONE: {
+                            field.set(data, DesensitizedUtil.mobilePhone(valueStr));
+                            break;
+                        }
+                        default: {
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
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
index ef3f455..6b49975 100644
--- 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
@@ -100,8 +100,9 @@
         String path = new File(System.getProperty("user.dir")).getAbsolutePath();
         path=path+filePath.getBasePath()+mainName;
         if (!FileUtil.exist(path)) {
-            FileUtil.mkdir(path);
+            FileUtil.del(path);
         }
+        FileUtil.mkdir(path);
         String m3u8FileName = path+"/" + mainName + ".m3u8";
 
         //下面这一串参数别乱动,经过调优的,1G视频大概需要10秒左右,如果是大佬随意改
@@ -119,7 +120,9 @@
                 .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")
+               // .addExtraArgs("-vsync", "2", "-c:v", "copy", "-c:a", "copy", "-tune", "fastdecode", "-hls_wrap", "0", "-hls_time", "10", "-hls_list_size", "0", "-threads", "12")  #新版本hls_wrap参数不支持
+               // .addExtraArgs("-vsync", "2", "-c:v", "copy", "-c:a", "copy", "-tune", "fastdecode", "-hls_flags", "delete_segments", "-hls_time", "10", "-hls_list_size", "0", "-threads", "12")
+                .addExtraArgs("-vsync", "2", "-c:v", "copy", "-c:a", "copy", "-tune", "fastdecode", "-hls_flags", "delete_segments", "-hls_time", "10", "-hls_list_size", "0", "-threads", "6")
                 .done();
 
         FFmpegExecutor executor = new FFmpegExecutor(ffmpeg, ffprobe);
diff --git a/exam-common/src/main/java/com/gkhy/exam/common/utils/SecurityUtils.java b/exam-common/src/main/java/com/gkhy/exam/common/utils/SecurityUtils.java
index 9b9fd90..ef46723 100644
--- a/exam-common/src/main/java/com/gkhy/exam/common/utils/SecurityUtils.java
+++ b/exam-common/src/main/java/com/gkhy/exam/common/utils/SecurityUtils.java
@@ -79,6 +79,22 @@
     }
 
 
+    /**
+     * 获取用户
+     **/
+    public static LoginUserDetails getLoginUserWithoutError()
+    {
+        try
+        {
+            return (LoginUserDetails) getAuthentication().getPrincipal();
+        }
+        catch (Exception e)
+        {
+            return null;
+        }
+    }
+
+
 
     /**
      * 获取Authentication
diff --git a/exam-common/src/main/java/com/gkhy/exam/common/utils/ServletUtils.java b/exam-common/src/main/java/com/gkhy/exam/common/utils/ServletUtils.java
index 2ee9df9..39763d3 100644
--- a/exam-common/src/main/java/com/gkhy/exam/common/utils/ServletUtils.java
+++ b/exam-common/src/main/java/com/gkhy/exam/common/utils/ServletUtils.java
@@ -110,6 +110,7 @@
     {
         try
         {
+            response.setStatus(200);
             response.setContentType("application/json");
             response.setCharacterEncoding("utf-8");
             response.getWriter().print(string);
diff --git a/exam-common/src/main/java/com/gkhy/exam/common/utils/html/EscapeUtil.java b/exam-common/src/main/java/com/gkhy/exam/common/utils/html/EscapeUtil.java
new file mode 100644
index 0000000..b682089
--- /dev/null
+++ b/exam-common/src/main/java/com/gkhy/exam/common/utils/html/EscapeUtil.java
@@ -0,0 +1,167 @@
+package com.gkhy.exam.common.utils.html;
+
+import com.gkhy.exam.common.utils.StringUtils;
+
+/**
+ * 转义和反转义工具类
+ * 
+ * @author ruoyi
+ */
+public class EscapeUtil
+{
+    public static final String RE_HTML_MARK = "(<[^<]*?>)|(<[\\s]*?/[^<]*?>)|(<[^<]*?/[\\s]*?>)";
+
+    private static final char[][] TEXT = new char[64][];
+
+    static
+    {
+        for (int i = 0; i < 64; i++)
+        {
+            TEXT[i] = new char[] { (char) i };
+        }
+
+        // special HTML characters
+        TEXT['\''] = "&#039;".toCharArray(); // 单引号
+        TEXT['"'] = "&#34;".toCharArray(); // 双引号
+        TEXT['&'] = "&#38;".toCharArray(); // &符
+        TEXT['<'] = "&#60;".toCharArray(); // 小于号
+        TEXT['>'] = "&#62;".toCharArray(); // 大于号
+    }
+
+    /**
+     * 转义文本中的HTML字符为安全的字符
+     * 
+     * @param text 被转义的文本
+     * @return 转义后的文本
+     */
+    public static String escape(String text)
+    {
+        return encode(text);
+    }
+
+    /**
+     * 还原被转义的HTML特殊字符
+     * 
+     * @param content 包含转义符的HTML内容
+     * @return 转换后的字符串
+     */
+    public static String unescape(String content)
+    {
+        return decode(content);
+    }
+
+    /**
+     * 清除所有HTML标签,但是不删除标签内的内容
+     * 
+     * @param content 文本
+     * @return 清除标签后的文本
+     */
+    public static String clean(String content)
+    {
+        return new HTMLFilter().filter(content);
+    }
+
+    /**
+     * Escape编码
+     * 
+     * @param text 被编码的文本
+     * @return 编码后的字符
+     */
+    private static String encode(String text)
+    {
+        if (StringUtils.isEmpty(text))
+        {
+            return StringUtils.EMPTY;
+        }
+
+        final StringBuilder tmp = new StringBuilder(text.length() * 6);
+        char c;
+        for (int i = 0; i < text.length(); i++)
+        {
+            c = text.charAt(i);
+            if (c < 256)
+            {
+                tmp.append("%");
+                if (c < 16)
+                {
+                    tmp.append("0");
+                }
+                tmp.append(Integer.toString(c, 16));
+            }
+            else
+            {
+                tmp.append("%u");
+                if (c <= 0xfff)
+                {
+                    // issue#I49JU8@Gitee
+                    tmp.append("0");
+                }
+                tmp.append(Integer.toString(c, 16));
+            }
+        }
+        return tmp.toString();
+    }
+
+    /**
+     * Escape解码
+     * 
+     * @param content 被转义的内容
+     * @return 解码后的字符串
+     */
+    public static String decode(String content)
+    {
+        if (StringUtils.isEmpty(content))
+        {
+            return content;
+        }
+
+        StringBuilder tmp = new StringBuilder(content.length());
+        int lastPos = 0, pos = 0;
+        char ch;
+        while (lastPos < content.length())
+        {
+            pos = content.indexOf("%", lastPos);
+            if (pos == lastPos)
+            {
+                if (content.charAt(pos + 1) == 'u')
+                {
+                    ch = (char) Integer.parseInt(content.substring(pos + 2, pos + 6), 16);
+                    tmp.append(ch);
+                    lastPos = pos + 6;
+                }
+                else
+                {
+                    ch = (char) Integer.parseInt(content.substring(pos + 1, pos + 3), 16);
+                    tmp.append(ch);
+                    lastPos = pos + 3;
+                }
+            }
+            else
+            {
+                if (pos == -1)
+                {
+                    tmp.append(content.substring(lastPos));
+                    lastPos = content.length();
+                }
+                else
+                {
+                    tmp.append(content.substring(lastPos, pos));
+                    lastPos = pos;
+                }
+            }
+        }
+        return tmp.toString();
+    }
+
+    public static void main(String[] args)
+    {
+        String html = "<script>alert(1);</script>";
+        String escape = EscapeUtil.escape(html);
+        // String html = "<scr<script>ipt>alert(\"XSS\")</scr<script>ipt>";
+        // String html = "<123";
+        // String html = "123>";
+        System.out.println("clean: " + EscapeUtil.clean(html));
+        System.out.println("escape: " + escape);
+        System.out.println("unescape: " + EscapeUtil.unescape(escape));
+    }
+}
diff --git a/exam-common/src/main/java/com/gkhy/exam/common/utils/html/HTMLFilter.java b/exam-common/src/main/java/com/gkhy/exam/common/utils/html/HTMLFilter.java
new file mode 100644
index 0000000..f31393d
--- /dev/null
+++ b/exam-common/src/main/java/com/gkhy/exam/common/utils/html/HTMLFilter.java
@@ -0,0 +1,566 @@
+package com.gkhy.exam.common.utils.html;
+
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * HTML过滤器,用于去除XSS漏洞隐患。
+ *
+ * @author ruoyi
+ */
+public final class HTMLFilter
+{
+    /**
+     * regex flag union representing /si modifiers in php
+     **/
+    private static final int REGEX_FLAGS_SI = Pattern.CASE_INSENSITIVE | Pattern.DOTALL;
+    private static final Pattern P_COMMENTS = Pattern.compile("<!--(.*?)-->", Pattern.DOTALL);
+    private static final Pattern P_COMMENT = Pattern.compile("^!--(.*)--$", REGEX_FLAGS_SI);
+    private static final Pattern P_TAGS = Pattern.compile("<(.*?)>", Pattern.DOTALL);
+    private static final Pattern P_END_TAG = Pattern.compile("^/([a-z0-9]+)", REGEX_FLAGS_SI);
+    private static final Pattern P_START_TAG = Pattern.compile("^([a-z0-9]+)(.*?)(/?)$", REGEX_FLAGS_SI);
+    private static final Pattern P_QUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)=([\"'])(.*?)\\2", REGEX_FLAGS_SI);
+    private static final Pattern P_UNQUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)(=)([^\"\\s']+)", REGEX_FLAGS_SI);
+    private static final Pattern P_PROTOCOL = Pattern.compile("^([^:]+):", REGEX_FLAGS_SI);
+    private static final Pattern P_ENTITY = Pattern.compile("&#(\\d+);?");
+    private static final Pattern P_ENTITY_UNICODE = Pattern.compile("&#x([0-9a-f]+);?");
+    private static final Pattern P_ENCODE = Pattern.compile("%([0-9a-f]{2});?");
+    private static final Pattern P_VALID_ENTITIES = Pattern.compile("&([^&;]*)(?=(;|&|$))");
+    private static final Pattern P_VALID_QUOTES = Pattern.compile("(>|^)([^<]+?)(<|$)", Pattern.DOTALL);
+    private static final Pattern P_END_ARROW = Pattern.compile("^>");
+    private static final Pattern P_BODY_TO_END = Pattern.compile("<([^>]*?)(?=<|$)");
+    private static final Pattern P_XML_CONTENT = Pattern.compile("(^|>)([^<]*?)(?=>)");
+    private static final Pattern P_STRAY_LEFT_ARROW = Pattern.compile("<([^>]*?)(?=<|$)");
+    private static final Pattern P_STRAY_RIGHT_ARROW = Pattern.compile("(^|>)([^<]*?)(?=>)");
+    private static final Pattern P_AMP = Pattern.compile("&");
+    private static final Pattern P_QUOTE = Pattern.compile("\"");
+    private static final Pattern P_LEFT_ARROW = Pattern.compile("<");
+    private static final Pattern P_RIGHT_ARROW = Pattern.compile(">");
+    private static final Pattern P_BOTH_ARROWS = Pattern.compile("<>");
+
+    // @xxx could grow large... maybe use sesat's ReferenceMap
+    private static final ConcurrentMap<String, Pattern> P_REMOVE_PAIR_BLANKS = new ConcurrentHashMap<>();
+    private static final ConcurrentMap<String, Pattern> P_REMOVE_SELF_BLANKS = new ConcurrentHashMap<>();
+
+    /**
+     * set of allowed html elements, along with allowed attributes for each element
+     **/
+    private final Map<String, List<String>> vAllowed;
+    /**
+     * counts of open tags for each (allowable) html element
+     **/
+    private final Map<String, Integer> vTagCounts = new HashMap<>();
+
+    /**
+     * html elements which must always be self-closing (e.g. "<img />")
+     **/
+    private final String[] vSelfClosingTags;
+    /**
+     * html elements which must always have separate opening and closing tags (e.g. "<b></b>")
+     **/
+    private final String[] vNeedClosingTags;
+    /**
+     * set of disallowed html elements
+     **/
+    private final String[] vDisallowed;
+    /**
+     * attributes which should be checked for valid protocols
+     **/
+    private final String[] vProtocolAtts;
+    /**
+     * allowed protocols
+     **/
+    private final String[] vAllowedProtocols;
+    /**
+     * tags which should be removed if they contain no content (e.g. "<b></b>" or "<b />")
+     **/
+    private final String[] vRemoveBlanks;
+    /**
+     * entities allowed within html markup
+     **/
+    private final String[] vAllowedEntities;
+    /**
+     * flag determining whether comments are allowed in input String.
+     */
+    private final boolean stripComment;
+    private final boolean encodeQuotes;
+    /**
+     * flag determining whether to try to make tags when presented with "unbalanced" angle brackets (e.g. "<b text </b>"
+     * becomes "<b> text </b>"). If set to false, unbalanced angle brackets will be html escaped.
+     */
+    private final boolean alwaysMakeTags;
+
+    /**
+     * Default constructor.
+     */
+    public HTMLFilter()
+    {
+        vAllowed = new HashMap<>();
+
+        final ArrayList<String> a_atts = new ArrayList<>();
+        a_atts.add("href");
+        a_atts.add("target");
+        vAllowed.put("a", a_atts);
+
+        final ArrayList<String> img_atts = new ArrayList<>();
+        img_atts.add("src");
+        img_atts.add("width");
+        img_atts.add("height");
+        img_atts.add("alt");
+        vAllowed.put("img", img_atts);
+
+        final ArrayList<String> no_atts = new ArrayList<>();
+        vAllowed.put("b", no_atts);
+        vAllowed.put("strong", no_atts);
+        vAllowed.put("i", no_atts);
+        vAllowed.put("em", no_atts);
+
+        vSelfClosingTags = new String[] { "img" };
+        vNeedClosingTags = new String[] { "a", "b", "strong", "i", "em" };
+        vDisallowed = new String[] {};
+        vAllowedProtocols = new String[] { "http", "mailto", "https" }; // no ftp.
+        vProtocolAtts = new String[] { "src", "href" };
+        vRemoveBlanks = new String[] { "a", "b", "strong", "i", "em" };
+        vAllowedEntities = new String[] { "amp", "gt", "lt", "quot" };
+        stripComment = true;
+        encodeQuotes = true;
+        alwaysMakeTags = false;
+    }
+
+    /**
+     * Map-parameter configurable constructor.
+     *
+     * @param conf map containing configuration. keys match field names.
+     */
+    @SuppressWarnings("unchecked")
+    public HTMLFilter(final Map<String, Object> conf)
+    {
+
+        assert conf.containsKey("vAllowed") : "configuration requires vAllowed";
+        assert conf.containsKey("vSelfClosingTags") : "configuration requires vSelfClosingTags";
+        assert conf.containsKey("vNeedClosingTags") : "configuration requires vNeedClosingTags";
+        assert conf.containsKey("vDisallowed") : "configuration requires vDisallowed";
+        assert conf.containsKey("vAllowedProtocols") : "configuration requires vAllowedProtocols";
+        assert conf.containsKey("vProtocolAtts") : "configuration requires vProtocolAtts";
+        assert conf.containsKey("vRemoveBlanks") : "configuration requires vRemoveBlanks";
+        assert conf.containsKey("vAllowedEntities") : "configuration requires vAllowedEntities";
+
+        vAllowed = Collections.unmodifiableMap((HashMap<String, List<String>>) conf.get("vAllowed"));
+        vSelfClosingTags = (String[]) conf.get("vSelfClosingTags");
+        vNeedClosingTags = (String[]) conf.get("vNeedClosingTags");
+        vDisallowed = (String[]) conf.get("vDisallowed");
+        vAllowedProtocols = (String[]) conf.get("vAllowedProtocols");
+        vProtocolAtts = (String[]) conf.get("vProtocolAtts");
+        vRemoveBlanks = (String[]) conf.get("vRemoveBlanks");
+        vAllowedEntities = (String[]) conf.get("vAllowedEntities");
+        stripComment = conf.containsKey("stripComment") ? (Boolean) conf.get("stripComment") : true;
+        encodeQuotes = conf.containsKey("encodeQuotes") ? (Boolean) conf.get("encodeQuotes") : true;
+        alwaysMakeTags = conf.containsKey("alwaysMakeTags") ? (Boolean) conf.get("alwaysMakeTags") : true;
+    }
+
+    private void reset()
+    {
+        vTagCounts.clear();
+    }
+
+    // ---------------------------------------------------------------
+    // my versions of some PHP library functions
+    public static String chr(final int decimal)
+    {
+        return String.valueOf((char) decimal);
+    }
+
+    public static String htmlSpecialChars(final String s)
+    {
+        String result = s;
+        result = regexReplace(P_AMP, "&amp;", result);
+        result = regexReplace(P_QUOTE, "&quot;", result);
+        result = regexReplace(P_LEFT_ARROW, "&lt;", result);
+        result = regexReplace(P_RIGHT_ARROW, "&gt;", result);
+        return result;
+    }
+
+    // ---------------------------------------------------------------
+
+    /**
+     * given a user submitted input String, filter out any invalid or restricted html.
+     *
+     * @param input text (i.e. submitted by a user) than may contain html
+     * @return "clean" version of input, with only valid, whitelisted html elements allowed
+     */
+    public String filter(final String input)
+    {
+        reset();
+        String s = input;
+
+        s = escapeComments(s);
+
+        s = balanceHTML(s);
+
+        s = checkTags(s);
+
+        s = processRemoveBlanks(s);
+
+        // s = validateEntities(s);
+
+        return s;
+    }
+
+    public boolean isAlwaysMakeTags()
+    {
+        return alwaysMakeTags;
+    }
+
+    public boolean isStripComments()
+    {
+        return stripComment;
+    }
+
+    private String escapeComments(final String s)
+    {
+        final Matcher m = P_COMMENTS.matcher(s);
+        final StringBuffer buf = new StringBuffer();
+        if (m.find())
+        {
+            final String match = m.group(1); // (.*?)
+            m.appendReplacement(buf, Matcher.quoteReplacement("<!--" + htmlSpecialChars(match) + "-->"));
+        }
+        m.appendTail(buf);
+
+        return buf.toString();
+    }
+
+    private String balanceHTML(String s)
+    {
+        if (alwaysMakeTags)
+        {
+            //
+            // try and form html
+            //
+            s = regexReplace(P_END_ARROW, "", s);
+            // 不追加结束标签
+            s = regexReplace(P_BODY_TO_END, "<$1>", s);
+            s = regexReplace(P_XML_CONTENT, "$1<$2", s);
+
+        }
+        else
+        {
+            //
+            // escape stray brackets
+            //
+            s = regexReplace(P_STRAY_LEFT_ARROW, "&lt;$1", s);
+            s = regexReplace(P_STRAY_RIGHT_ARROW, "$1$2&gt;<", s);
+
+            //
+            // the last regexp causes '<>' entities to appear
+            // (we need to do a lookahead assertion so that the last bracket can
+            // be used in the next pass of the regexp)
+            //
+            s = regexReplace(P_BOTH_ARROWS, "", s);
+        }
+
+        return s;
+    }
+
+    private String checkTags(String s)
+    {
+        Matcher m = P_TAGS.matcher(s);
+
+        final StringBuffer buf = new StringBuffer();
+        while (m.find())
+        {
+            String replaceStr = m.group(1);
+            replaceStr = processTag(replaceStr);
+            m.appendReplacement(buf, Matcher.quoteReplacement(replaceStr));
+        }
+        m.appendTail(buf);
+
+        // these get tallied in processTag
+        // (remember to reset before subsequent calls to filter method)
+        final StringBuilder sBuilder = new StringBuilder(buf.toString());
+        for (String key : vTagCounts.keySet())
+        {
+            for (int ii = 0; ii < vTagCounts.get(key); ii++)
+            {
+                sBuilder.append("</").append(key).append(">");
+            }
+        }
+        s = sBuilder.toString();
+
+        return s;
+    }
+
+    private String processRemoveBlanks(final String s)
+    {
+        String result = s;
+        for (String tag : vRemoveBlanks)
+        {
+            if (!P_REMOVE_PAIR_BLANKS.containsKey(tag))
+            {
+                P_REMOVE_PAIR_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?></" + tag + ">"));
+            }
+            result = regexReplace(P_REMOVE_PAIR_BLANKS.get(tag), "", result);
+            if (!P_REMOVE_SELF_BLANKS.containsKey(tag))
+            {
+                P_REMOVE_SELF_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?/>"));
+            }
+            result = regexReplace(P_REMOVE_SELF_BLANKS.get(tag), "", result);
+        }
+
+        return result;
+    }
+
+    private static String regexReplace(final Pattern regex_pattern, final String replacement, final String s)
+    {
+        Matcher m = regex_pattern.matcher(s);
+        return m.replaceAll(replacement);
+    }
+
+    private String processTag(final String s)
+    {
+        // ending tags
+        Matcher m = P_END_TAG.matcher(s);
+        if (m.find())
+        {
+            final String name = m.group(1).toLowerCase();
+            if (allowed(name))
+            {
+                if (!inArray(name, vSelfClosingTags))
+                {
+                    if (vTagCounts.containsKey(name))
+                    {
+                        vTagCounts.put(name, vTagCounts.get(name) - 1);
+                        return "</" + name + ">";
+                    }
+                }
+            }
+        }
+
+        // starting tags
+        m = P_START_TAG.matcher(s);
+        if (m.find())
+        {
+            final String name = m.group(1).toLowerCase();
+            final String body = m.group(2);
+            String ending = m.group(3);
+
+            // debug( "in a starting tag, name='" + name + "'; body='" + body + "'; ending='" + ending + "'" );
+            if (allowed(name))
+            {
+                final StringBuilder params = new StringBuilder();
+
+                final Matcher m2 = P_QUOTED_ATTRIBUTES.matcher(body);
+                final Matcher m3 = P_UNQUOTED_ATTRIBUTES.matcher(body);
+                final List<String> paramNames = new ArrayList<>();
+                final List<String> paramValues = new ArrayList<>();
+                while (m2.find())
+                {
+                    paramNames.add(m2.group(1)); // ([a-z0-9]+)
+                    paramValues.add(m2.group(3)); // (.*?)
+                }
+                while (m3.find())
+                {
+                    paramNames.add(m3.group(1)); // ([a-z0-9]+)
+                    paramValues.add(m3.group(3)); // ([^\"\\s']+)
+                }
+
+                String paramName, paramValue;
+                for (int ii = 0; ii < paramNames.size(); ii++)
+                {
+                    paramName = paramNames.get(ii).toLowerCase();
+                    paramValue = paramValues.get(ii);
+
+                    // debug( "paramName='" + paramName + "'" );
+                    // debug( "paramValue='" + paramValue + "'" );
+                    // debug( "allowed? " + vAllowed.get( name ).contains( paramName ) );
+
+                    if (allowedAttribute(name, paramName))
+                    {
+                        if (inArray(paramName, vProtocolAtts))
+                        {
+                            paramValue = processParamProtocol(paramValue);
+                        }
+                        params.append(' ').append(paramName).append("=\\\"").append(paramValue).append("\\\"");
+                    }
+                }
+
+                if (inArray(name, vSelfClosingTags))
+                {
+                    ending = " /";
+                }
+
+                if (inArray(name, vNeedClosingTags))
+                {
+                    ending = "";
+                }
+
+                if (ending == null || ending.length() < 1)
+                {
+                    if (vTagCounts.containsKey(name))
+                    {
+                        vTagCounts.put(name, vTagCounts.get(name) + 1);
+                    }
+                    else
+                    {
+                        vTagCounts.put(name, 1);
+                    }
+                }
+                else
+                {
+                    ending = " /";
+                }
+                return "<" + name + params + ending + ">";
+            }
+            else
+            {
+                return "";
+            }
+        }
+
+        // comments
+        m = P_COMMENT.matcher(s);
+        if (!stripComment && m.find())
+        {
+            return "<" + m.group() + ">";
+        }
+
+        return "";
+    }
+
+    private String processParamProtocol(String s)
+    {
+        s = decodeEntities(s);
+        final Matcher m = P_PROTOCOL.matcher(s);
+        if (m.find())
+        {
+            final String protocol = m.group(1);
+            if (!inArray(protocol, vAllowedProtocols))
+            {
+                // bad protocol, turn into local anchor link instead
+                s = "#" + s.substring(protocol.length() + 1);
+                if (s.startsWith("#//"))
+                {
+                    s = "#" + s.substring(3);
+                }
+            }
+        }
+
+        return s;
+    }
+
+    private String decodeEntities(String s)
+    {
+        StringBuffer buf = new StringBuffer();
+
+        Matcher m = P_ENTITY.matcher(s);
+        while (m.find())
+        {
+            final String match = m.group(1);
+            final int decimal = Integer.decode(match).intValue();
+            m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
+        }
+        m.appendTail(buf);
+        s = buf.toString();
+
+        buf = new StringBuffer();
+        m = P_ENTITY_UNICODE.matcher(s);
+        while (m.find())
+        {
+            final String match = m.group(1);
+            final int decimal = Integer.valueOf(match, 16).intValue();
+            m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
+        }
+        m.appendTail(buf);
+        s = buf.toString();
+
+        buf = new StringBuffer();
+        m = P_ENCODE.matcher(s);
+        while (m.find())
+        {
+            final String match = m.group(1);
+            final int decimal = Integer.valueOf(match, 16).intValue();
+            m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
+        }
+        m.appendTail(buf);
+        s = buf.toString();
+
+        s = validateEntities(s);
+        return s;
+    }
+
+    private String validateEntities(final String s)
+    {
+        StringBuffer buf = new StringBuffer();
+
+        // validate entities throughout the string
+        Matcher m = P_VALID_ENTITIES.matcher(s);
+        while (m.find())
+        {
+            final String one = m.group(1); // ([^&;]*)
+            final String two = m.group(2); // (?=(;|&|$))
+            m.appendReplacement(buf, Matcher.quoteReplacement(checkEntity(one, two)));
+        }
+        m.appendTail(buf);
+
+        return encodeQuotes(buf.toString());
+    }
+
+    private String encodeQuotes(final String s)
+    {
+        if (encodeQuotes)
+        {
+            StringBuffer buf = new StringBuffer();
+            Matcher m = P_VALID_QUOTES.matcher(s);
+            while (m.find())
+            {
+                final String one = m.group(1); // (>|^)
+                final String two = m.group(2); // ([^<]+?)
+                final String three = m.group(3); // (<|$)
+                // 不替换双引号为&quot;,防止json格式无效 regexReplace(P_QUOTE, "&quot;", two)
+                m.appendReplacement(buf, Matcher.quoteReplacement(one + two + three));
+            }
+            m.appendTail(buf);
+            return buf.toString();
+        }
+        else
+        {
+            return s;
+        }
+    }
+
+    private String checkEntity(final String preamble, final String term)
+    {
+
+        return ";".equals(term) && isValidEntity(preamble) ? '&' + preamble : "&amp;" + preamble;
+    }
+
+    private boolean isValidEntity(final String entity)
+    {
+        return inArray(entity, vAllowedEntities);
+    }
+
+    private static boolean inArray(final String s, final String[] array)
+    {
+        for (String item : array)
+        {
+            if (item != null && item.equals(s))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean allowed(final String name)
+    {
+        return (vAllowed.isEmpty() || vAllowed.containsKey(name)) && !inArray(name, vDisallowed);
+    }
+
+    private boolean allowedAttribute(final String name, final String paramName)
+    {
+        return allowed(name) && (vAllowed.isEmpty() || vAllowed.get(name).contains(paramName));
+    }
+}
\ No newline at end of file
diff --git a/exam-framework/src/main/java/com/gkhy/exam/framework/aspectj/DataDesensitizationAspect.java b/exam-framework/src/main/java/com/gkhy/exam/framework/aspectj/DataDesensitizationAspect.java
new file mode 100644
index 0000000..140c003
--- /dev/null
+++ b/exam-framework/src/main/java/com/gkhy/exam/framework/aspectj/DataDesensitizationAspect.java
@@ -0,0 +1,44 @@
+package com.gkhy.exam.framework.aspectj;
+
+import com.gkhy.exam.common.annotation.DataDesensitization;
+import com.gkhy.exam.common.utils.DesenseUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.http.HttpServletRequest;
+import java.lang.reflect.Method;
+
+/**
+ * 数据脱密
+ */
+@Aspect
+@Component
+@Slf4j
+public class DataDesensitizationAspect {
+    @Autowired
+    private HttpServletRequest request;
+    @Pointcut("@annotation(com.gkhy.exam.common.annotation.DataDesensitization)")
+    public void pointcut(){}
+
+    @Around("pointcut()")
+    public Object doaround(ProceedingJoinPoint point) throws Throwable {
+        Object object=point.proceed();
+        String uri = request.getRequestURI();
+//        if(!uri.startsWith("/app/api")){
+//            return object;
+//        }
+        MethodSignature signature = (MethodSignature) point.getSignature();
+        Method method = signature.getMethod();
+        if(!method.isAnnotationPresent(DataDesensitization.class)){
+            return object;
+        }
+        DesenseUtil.assertResult(object);
+        return object;
+    }
+}
diff --git a/exam-framework/src/main/java/com/gkhy/exam/framework/aspectj/LogAspect.java b/exam-framework/src/main/java/com/gkhy/exam/framework/aspectj/LogAspect.java
index 1cb5a3c..19b9e4d 100644
--- a/exam-framework/src/main/java/com/gkhy/exam/framework/aspectj/LogAspect.java
+++ b/exam-framework/src/main/java/com/gkhy/exam/framework/aspectj/LogAspect.java
@@ -1,34 +1,34 @@
 package com.gkhy.exam.framework.aspectj;
 
-import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.URLUtil;
+import cn.hutool.extra.servlet.ServletUtil;
+import cn.hutool.json.JSONObject;
 import com.alibaba.fastjson2.JSON;
-import com.gkhy.exam.common.annotation.Log;
 import com.gkhy.exam.common.domain.entity.SysUser;
-import com.gkhy.exam.common.enums.BusinessStatus;
-import com.gkhy.exam.common.filter.PropertyPreExcludeFilter;
 import com.gkhy.exam.common.utils.SecurityUtils;
-import com.gkhy.exam.common.utils.ServletUtils;
 import com.gkhy.exam.common.utils.StringUtils;
-import com.gkhy.exam.system.domain.SysOperLog;
 import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.ArrayUtils;
 import org.aspectj.lang.JoinPoint;
-import org.aspectj.lang.annotation.AfterReturning;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.Signature;
 import org.aspectj.lang.annotation.AfterThrowing;
+import org.aspectj.lang.annotation.Around;
 import org.aspectj.lang.annotation.Aspect;
-import org.aspectj.lang.annotation.Before;
+import org.aspectj.lang.annotation.Pointcut;
+import org.aspectj.lang.reflect.MethodSignature;
 import org.springframework.core.NamedThreadLocal;
-import org.springframework.http.HttpMethod;
 import org.springframework.stereotype.Component;
-import org.springframework.validation.BindingResult;
-import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
 
-import javax.servlet.ServletRequest;
 import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.util.Collection;
-import java.util.Collections;
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -42,204 +42,105 @@
     public static final String[] EXCLUDE_PROPERTIES = { "password", "oldPassword", "newPassword", "confirmPassword" };
     private static final ThreadLocal<Long> TIME_THREADLOCAL=new NamedThreadLocal<>("Cost Time");
 
-    /**
-     * 处理请求前执行
-     * @param joinPoint
-     * @param controllerLog
-     */
-    @Before(value = "@annotation(controllerLog)")
-    public void doBefore(JoinPoint joinPoint, Log controllerLog){
-        TIME_THREADLOCAL.set(System.currentTimeMillis());
+    @Pointcut("execution(public * com.gkhy.exam.*.controller..*.*(..))")
+    public void logPointCut(){
+
     }
+
+
+
 
     /**
      * 处理完请求后执行
-     * @param joinPoint
-     * @param controllerLog
-     * @param jsonResult
+     *
+     * @param joinPoint 切点
      */
-    @AfterReturning(pointcut = "@annotation(controllerLog)",returning ="jsonResult" )
-    public void doAfterReturning(JoinPoint joinPoint,Log controllerLog,Object jsonResult){
-        handleLog(joinPoint,controllerLog,null,jsonResult);
+    @Around("logPointCut()")
+    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable{
+        SysUser user= SecurityUtils.getLoginUserWithoutError()!=null?SecurityUtils.getLoginUserWithoutError().getUser():null;
+        long startTime = System.currentTimeMillis();
+        //获取当前请求对象
+        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
+        HttpServletRequest request = attributes.getRequest();
+        Signature signature = joinPoint.getSignature();
+        MethodSignature methodSignature = (MethodSignature) signature;
+        Method method = methodSignature.getMethod();
+        StringBuffer requestURL = request.getRequestURL();
+        JSONObject webLog = new JSONObject();
+        String urlStr = request.getRequestURL().toString();
+        webLog.put("basePath", StringUtils.removeSuffix(urlStr, URLUtil.url(urlStr).getPath()));
+        webLog.put("ip", ServletUtil.getClientIP(request,null));
+        webLog.put("method",request.getMethod());
+        Object params=getParameter(method, joinPoint.getArgs());
+
+        webLog.put("parameter",params);
+        webLog.put("uri",request.getRequestURI());
+        webLog.put("url",requestURL.toString());
+        if(user!=null) {
+            webLog.put("userName", user.getName());
+        }
+        log.info(webLog.toString());
+        Object result = joinPoint.proceed();
+        if (result == null) {
+            //如果切到了 没有返回类型的void方法,这里直接返回
+            return null;
+        }
+        long endTime = System.currentTimeMillis();
+        webLog.put("result",StringUtils.sub(JSON.toJSONString(result),0,2000));
+        webLog.put("spendTime",endTime - startTime);
+        log.info(webLog.toString());
+        return result;
     }
+
+
+
 
     /**
      * 拦截异常操作
      * @param joinPoint
-     * @param controllerLog
      * @param e
      */
-    @AfterThrowing(value = "@annotation(controllerLog)",throwing = "e")
-    public void doAfterThrowing(JoinPoint joinPoint,Log controllerLog,Exception e){
-        handleLog(joinPoint,controllerLog,e,null);
+    @AfterThrowing(value = "logPointCut()", throwing = "e")
+    public void doAfterThrowing(JoinPoint joinPoint,Exception e){
+        //获取当前请求对象
+        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
+        HttpServletRequest request = attributes.getRequest();
+        String urlStr = request.getRequestURL().toString();
+        log.error("@AfterThrowing异常通知:url={},出错了error_message={}", urlStr,e.getMessage());
     }
 
-    protected void handleLog(final JoinPoint joinPoint,Log controllerLog,final Exception e,Object jsonResult){
-        try{
-            HttpServletRequest request= ServletUtils.getRequest();
-            SysUser user= SecurityUtils.getLoginUser().getUser();
-            SysOperLog operLog=new SysOperLog();
-            operLog.setStatus(BusinessStatus.SUCCESS.ordinal());
 
-            String ip= cn.hutool.extra.servlet.ServletUtil.getClientIP(request);
-            operLog.setOperIp(ip);
-            operLog.setOperUrl(StringUtils.sub(request.getRequestURI(),0,255));
-            if(user!=null){
-                operLog.setOperName(user.getUsername());
+    /**
+     * 根据方法和传入的参数获取请求参数
+     */
+    private Object getParameter(Method method, Object[] args) {
+        List<Object> argList = new ArrayList<>();
+        Parameter[] parameters = method.getParameters();
+        for (int i = 0; i < parameters.length; i++) {
+            //将RequestBody注解修饰的参数作为请求参数
+            RequestBody requestBody = parameters[i].getAnnotation(RequestBody.class);
+            if (requestBody != null) {
+                argList.add(args[i]);
             }
-            if(e!=null){
-                operLog.setStatus(BusinessStatus.FAIL.ordinal());
-                operLog.setErrorMsg(StringUtils.sub(e.getMessage(),0,2000));
-            }
-            String className=joinPoint.getTarget().getClass().getName();
-            String methodName=joinPoint.getSignature().getName();
-            operLog.setMethod(className+"."+methodName+"()");
-            operLog.setRequestMethod(request.getMethod());
-            getControllerMethodDescription(joinPoint, controllerLog, operLog, jsonResult);
-            operLog.setCostTime(System.currentTimeMillis()-TIME_THREADLOCAL.get());
-            log.info(JSON.toJSONString(operLog));
-           // AsyncManager.me().execute(AsyncFactory.recordOper(operLog));
-        }catch (Exception exp){
-            log.error("异常信息:{}",exp.getMessage());
-            exp.printStackTrace();
-        }finally {
-            TIME_THREADLOCAL.remove();
-        }
-    }
-
-    /**
-     * 获取注解中对方法的描述信息 用于Controller层注解
-     *
-     * @param log 日志
-     * @param operLog 操作日志
-     * @throws Exception
-     */
-    public void getControllerMethodDescription(JoinPoint joinPoint, Log log, SysOperLog operLog, Object jsonResult) throws Exception
-    {
-        // 设置action动作
-        operLog.setBusinessType(log.businessType().ordinal());
-        // 设置标题
-        operLog.setTitle(log.title());
-        // 设置操作人类别
-        operLog.setOperatorType(log.operatorType().ordinal());
-        // 是否需要保存request,参数和值
-        if (log.isSaveRequestData())
-        {
-            // 获取参数的信息,传入到数据库中。
-            setRequestValue(joinPoint, operLog, log.excludeParamNames());
-        }
-        // 是否需要保存response,参数和值
-        if (log.isSaveResponseData() && ObjectUtil.isNotNull(jsonResult))
-        {
-            operLog.setJsonResult(StringUtils.sub(JSON.toJSONString(jsonResult), 0, 2000));
-        }
-    }
-
-    /**
-     * 获取请求的参数,放到log中
-     *
-     * @param operLog 操作日志
-     * @throws Exception 异常
-     */
-    private void setRequestValue(JoinPoint joinPoint, SysOperLog operLog, String[] excludeParamNames) throws Exception
-    {
-        Map<?, ?> paramsMap = getParamMap(ServletUtils.getRequest());
-        String requestMethod = operLog.getRequestMethod();
-        if (ObjectUtil.isEmpty(paramsMap)
-                && (HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod)))
-        {
-            String params = argsArrayToString(joinPoint.getArgs(), excludeParamNames);
-            operLog.setOperParam(StringUtils.sub(params, 0, 2000));
-        }
-        else{
-            operLog.setOperParam(StringUtils.sub(JSON.toJSONString(paramsMap, excludePropertyPreFilter(excludeParamNames)), 0, 2000));
-        }
-    }
-
-    /**
-     * 获得所有请求参数
-     *
-     * @param request 请求对象{@link ServletRequest}
-     * @return Map
-     */
-    private  Map<String, String> getParamMap(ServletRequest request)
-    {
-        Map<String, String> params = new HashMap<>();
-        Map<String, String[]> map = request.getParameterMap();
-        for (Map.Entry<String, String[]> entry : Collections.unmodifiableMap(map).entrySet())
-        {
-            params.put(entry.getKey(), StringUtils.join(",",entry.getValue()));
-        }
-        return params;
-    }
-
-    /**
-     * 参数拼装
-     */
-    private String argsArrayToString(Object[] paramsArray, String[] excludeParamNames)
-    {
-        String params = "";
-        if (paramsArray != null && paramsArray.length > 0)
-        {
-            for (Object o : paramsArray)
-            {
-                if (ObjectUtil.isNotNull(o) && !isFilterObject(o))
-                {
-                    try
-                    {
-                        String jsonObj = JSON.toJSONString(o, excludePropertyPreFilter(excludeParamNames));
-                        params += jsonObj.toString() + " ";
-                    }
-                    catch (Exception e)
-                    {
-                    }
+            //将RequestParam注解修饰的参数作为请求参数
+            RequestParam requestParam = parameters[i].getAnnotation(RequestParam.class);
+            if (requestParam != null) {
+                Map<String, Object> map = new HashMap<>();
+                String key = parameters[i].getName();
+                if (StringUtils.isNotEmpty(requestParam.value())) {
+                    key = requestParam.value();
                 }
+                map.put(key, args[i]);
+                argList.add(map);
             }
         }
-        return params.trim();
-    }
-
-    /**
-     * 忽略敏感属性
-     */
-    public PropertyPreExcludeFilter excludePropertyPreFilter(String[] excludeParamNames)
-    {
-        return new PropertyPreExcludeFilter().addExcludes(ArrayUtils.addAll(EXCLUDE_PROPERTIES, excludeParamNames));
-    }
-
-    /**
-     * 判断是否需要过滤的对象。
-     *
-     * @param o 对象信息。
-     * @return 如果是需要过滤的对象,则返回true;否则返回false。
-     */
-    @SuppressWarnings("rawtypes")
-    public boolean isFilterObject(final Object o)
-    {
-        Class<?> clazz = o.getClass();
-        if (clazz.isArray())
-        {
-            return clazz.getComponentType().isAssignableFrom(MultipartFile.class);
+        if (argList.size() == 0) {
+            return null;
+        } else if (argList.size() == 1) {
+            return argList.get(0);
+        } else {
+            return argList;
         }
-        else if (Collection.class.isAssignableFrom(clazz))
-        {
-            Collection collection = (Collection) o;
-            for (Object value : collection)
-            {
-                return value instanceof MultipartFile;
-            }
-        }
-        else if (Map.class.isAssignableFrom(clazz))
-        {
-            Map map = (Map) o;
-            for (Object value : map.entrySet())
-            {
-                Map.Entry entry = (Map.Entry) value;
-                return entry.getValue() instanceof MultipartFile;
-            }
-        }
-        return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse
-                || o instanceof BindingResult;
     }
 
 
diff --git a/exam-framework/src/main/java/com/gkhy/exam/framework/config/ApplicationConfig.java b/exam-framework/src/main/java/com/gkhy/exam/framework/config/ApplicationConfig.java
index 29339e8..2076f61 100644
--- a/exam-framework/src/main/java/com/gkhy/exam/framework/config/ApplicationConfig.java
+++ b/exam-framework/src/main/java/com/gkhy/exam/framework/config/ApplicationConfig.java
@@ -6,7 +6,6 @@
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
 import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Conditional;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.EnableAspectJAutoProxy;
 import org.springframework.web.cors.CorsConfiguration;
@@ -53,6 +52,13 @@
         final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
         final CorsConfiguration corsConfiguration = new CorsConfiguration();
         //是否允许请求带有验证信息
+//        corsConfiguration.setAllowCredentials(true);
+//        corsConfiguration.setAllowedOrigins(Arrays.asList("*"));
+//        corsConfiguration.setAllowedMethods(Arrays.asList("*"));
+//        corsConfiguration.setAllowCredentials(true);
+//        corsConfiguration.setMaxAge(168000L);
+
+        //是否允许请求带有验证信息
         corsConfiguration.setAllowCredentials(true);
         // 允许访问的客户端域名
         corsConfiguration.addAllowedOriginPattern("*");
@@ -60,6 +66,7 @@
         corsConfiguration.addAllowedHeader("*");
         // 允许访问的方法名,GET POST等
         corsConfiguration.addAllowedMethod("*");
+        corsConfiguration.setMaxAge(168000L);
         urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
         return new CorsFilter(urlBasedCorsConfigurationSource);
     }
diff --git a/exam-framework/src/main/java/com/gkhy/exam/framework/config/FastjsonConfig.java b/exam-framework/src/main/java/com/gkhy/exam/framework/config/FastjsonConfig.java
new file mode 100644
index 0000000..bc5ca7f
--- /dev/null
+++ b/exam-framework/src/main/java/com/gkhy/exam/framework/config/FastjsonConfig.java
@@ -0,0 +1,68 @@
+package com.gkhy.exam.framework.config;
+
+import com.alibaba.fastjson2.JSONWriter;
+import com.alibaba.fastjson2.support.config.FastJsonConfig;
+import com.alibaba.fastjson2.support.spring.http.converter.FastJsonHttpMessageConverter;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.MediaType;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+
+@Configuration
+public class FastjsonConfig implements WebMvcConfigurer {
+
+    @Override
+    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
+        FastJsonConfig config=new FastJsonConfig();
+        config.setDateFormat("yyyy-MM-dd HH:mm:ss");
+        config.setCharset(StandardCharsets.UTF_8);
+        config.setWriterFeatures(
+                JSONWriter.Feature.WriteNullListAsEmpty,
+                //json格式化
+                JSONWriter.Feature.PrettyFormat,
+                //输出map中value为null的数据
+                JSONWriter.Feature.WriteMapNullValue,
+                //输出boolean 为 false
+                JSONWriter.Feature.WriteNullBooleanAsFalse,
+                //输出list 为 []
+                JSONWriter.Feature.WriteNullListAsEmpty,
+                //输出number 为 0
+                JSONWriter.Feature.WriteNullNumberAsZero,
+                //输出字符串 为 ""
+                JSONWriter.Feature.WriteNullStringAsEmpty,
+                //对map进行排序
+                JSONWriter.Feature.MapSortField
+        );
+        // 2. 添加fastjson转换器
+        FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
+        List<MediaType> supportedMediaTypes = new ArrayList<>();
+
+        // 3. 添加支持的媒体类型
+        supportedMediaTypes.add(MediaType.APPLICATION_JSON);
+        supportedMediaTypes.add(MediaType.APPLICATION_ATOM_XML);
+        supportedMediaTypes.add(MediaType.APPLICATION_FORM_URLENCODED);
+        supportedMediaTypes.add(MediaType.APPLICATION_OCTET_STREAM);
+        supportedMediaTypes.add(MediaType.APPLICATION_PDF);
+        supportedMediaTypes.add(MediaType.APPLICATION_RSS_XML);
+        supportedMediaTypes.add(MediaType.APPLICATION_XHTML_XML);
+        supportedMediaTypes.add(MediaType.APPLICATION_XML);
+        supportedMediaTypes.add(MediaType.IMAGE_GIF);
+        supportedMediaTypes.add(MediaType.IMAGE_JPEG);
+        supportedMediaTypes.add(MediaType.IMAGE_PNG);
+        supportedMediaTypes.add(MediaType.TEXT_EVENT_STREAM);
+        supportedMediaTypes.add(MediaType.TEXT_HTML);
+        supportedMediaTypes.add(MediaType.TEXT_MARKDOWN);
+        supportedMediaTypes.add(MediaType.TEXT_PLAIN);
+        supportedMediaTypes.add(MediaType.TEXT_XML);
+
+        converter.setSupportedMediaTypes(supportedMediaTypes);
+
+        //4 将convert添加到converters
+        converter.setFastJsonConfig(config);
+        converters.add(0,converter);
+    }
+}
diff --git a/exam-framework/src/main/java/com/gkhy/exam/framework/config/FilterConfig.java b/exam-framework/src/main/java/com/gkhy/exam/framework/config/FilterConfig.java
new file mode 100644
index 0000000..78f5713
--- /dev/null
+++ b/exam-framework/src/main/java/com/gkhy/exam/framework/config/FilterConfig.java
@@ -0,0 +1,64 @@
+package com.gkhy.exam.framework.config;
+
+
+import com.gkhy.exam.common.filter.RepeatableFilter;
+import com.gkhy.exam.common.filter.XssFilter;
+import com.gkhy.exam.common.utils.StringUtils;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import javax.servlet.DispatcherType;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Filter配置
+ *
+ */
+@Configuration
+public class FilterConfig
+{
+    @Value("${xss.excludes}")
+    private String excludes;
+
+    @Value("${xss.urlPatterns}")
+    private String urlPatterns;
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    @Bean
+    @ConditionalOnProperty(value = "xss.enabled", havingValue = "true")
+    public FilterRegistrationBean xssFilterRegistration()
+    {
+        FilterRegistrationBean registration = new FilterRegistrationBean();
+        registration.setDispatcherTypes(DispatcherType.REQUEST);
+        registration.setFilter(new XssFilter());
+        StringUtils.split(urlPatterns,10);
+        registration.addUrlPatterns(String.join(",",StringUtils.split(urlPatterns, ",")));
+        registration.setName("xssFilter");
+        registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE);
+        Map<String, String> initParameters = new HashMap<String, String>();
+        initParameters.put("excludes", excludes);
+        registration.setInitParameters(initParameters);
+        return registration;
+    }
+
+    /**
+     * 重复请求校验
+     * @return
+     */
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    @Bean
+    public FilterRegistrationBean someFilterRegistration()
+    {
+        FilterRegistrationBean registration = new FilterRegistrationBean();
+        registration.setFilter(new RepeatableFilter());
+        registration.addUrlPatterns("/*");
+        registration.setName("repeatableFilter");
+        registration.setOrder(FilterRegistrationBean.LOWEST_PRECEDENCE);
+        return registration;
+    }
+
+}
diff --git a/exam-framework/src/main/java/com/gkhy/exam/framework/event/PaperStudentEvent.java b/exam-framework/src/main/java/com/gkhy/exam/framework/event/PaperStudentEvent.java
new file mode 100644
index 0000000..376a06a
--- /dev/null
+++ b/exam-framework/src/main/java/com/gkhy/exam/framework/event/PaperStudentEvent.java
@@ -0,0 +1,16 @@
+package com.gkhy.exam.framework.event;
+
+import com.gkhy.exam.system.domain.ExPaperStudent;
+import org.springframework.context.ApplicationEvent;
+
+/**
+ *
+ */
+public class PaperStudentEvent extends ApplicationEvent {
+    private ExPaperStudent paperStudent;
+
+    public PaperStudentEvent(ExPaperStudent paperStudent) {
+        super(paperStudent);
+        this.paperStudent=paperStudent;
+    }
+}
diff --git a/exam-framework/src/main/java/com/gkhy/exam/framework/event/PaperStudentListener.java b/exam-framework/src/main/java/com/gkhy/exam/framework/event/PaperStudentListener.java
new file mode 100644
index 0000000..266db33
--- /dev/null
+++ b/exam-framework/src/main/java/com/gkhy/exam/framework/event/PaperStudentListener.java
@@ -0,0 +1,82 @@
+package com.gkhy.exam.framework.event;
+
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.gkhy.exam.common.enums.PaperStudentStateEnum;
+import com.gkhy.exam.common.enums.QuestionTypeEnum;
+import com.gkhy.exam.common.enums.StudentAnswerPassEnum;
+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.ExStudentAnswer;
+import com.gkhy.exam.system.service.ExExamPaperService;
+import com.gkhy.exam.system.service.ExPaperStudentService;
+import com.gkhy.exam.system.service.ExQuestionService;
+import com.gkhy.exam.system.service.ExStudentAnswerService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.event.EventListener;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Component
+public class PaperStudentListener {
+    @Autowired
+    private ExExamPaperService examPaperService;
+    @Autowired
+    private ExStudentAnswerService studentAnswerService;
+    @Autowired
+    private ExQuestionService questionService;
+    @Autowired
+    private ExPaperStudentService paperStudentService;
+
+    @EventListener
+    public void PaperStudentListener(ExPaperStudent paperStudent){
+        ExExamPaper examPaper=examPaperService.getById(paperStudent.getPaperId());
+        List<ExStudentAnswer> studentAnswerList=studentAnswerService.list(Wrappers.<ExStudentAnswer>lambdaQuery()
+                .eq(true,ExStudentAnswer::getStudentId,paperStudent.getStudentId())
+                .eq(true,ExStudentAnswer::getPaperId,paperStudent.getPaperId()));
+        List<ExQuestion> questionList=questionService.selectQuestionByPaperId(paperStudent.getPaperId());
+        Map<Long, ExQuestion> collectMap = questionList.stream().collect(Collectors.toMap(ExQuestion::getId, k -> k));
+        Integer totalScore=0;
+        for(ExStudentAnswer studentAnswer:studentAnswerList){
+            ExQuestion question=collectMap.get(studentAnswer.getQuestionId());
+            if(question.getQuestionType().equals(QuestionTypeEnum.EASY.getCode())){
+                studentAnswer.setPassed(StudentAnswerPassEnum.WAIT_REVIEW.getCode());
+            }else{
+                if(studentAnswer.getAnswer().equals(question.getAnswer())){
+                    studentAnswer.setPassed(StudentAnswerPassEnum.CORRECT.getCode());
+                    studentAnswer.setScore(getScore(examPaper,question.getQuestionType()));
+                    totalScore=totalScore+studentAnswer.getScore();
+                }else{
+                    studentAnswer.setPassed(StudentAnswerPassEnum.ERROR.getCode());
+                    studentAnswer.setScore(0);
+                }
+            }
+        }
+        studentAnswerService.updateBatchById(studentAnswerList);
+        if(Optional.ofNullable(examPaper.getEasyNum()).orElse(0)<=0){
+            //没有简答题,直接批改试卷
+            paperStudent.setScore(totalScore);
+            paperStudent.setState(PaperStudentStateEnum.DONE_REVIEW.getCode());
+            paperStudentService.updateById(paperStudent);
+        }
+    }
+
+    private Integer getScore(ExExamPaper examPaper,Integer questionType){
+        if(questionType.equals(QuestionTypeEnum.SINGLE.getCode())){
+            return examPaper.getSingleScore();
+        }else if(questionType.equals(QuestionTypeEnum.MULTI.getCode())){
+            return examPaper.getMultiScore();
+        }else if(questionType.equals(QuestionTypeEnum.JUDGE.getCode())){
+            return examPaper.getJudgeScore();
+        }else if(questionType.equals(QuestionTypeEnum.EASY.getCode())){
+            return examPaper.getEasyScore();
+        }
+        return 0;
+    }
+}
diff --git a/exam-framework/src/main/java/com/gkhy/exam/framework/exception/GlobalExceptionHandler.java b/exam-framework/src/main/java/com/gkhy/exam/framework/exception/GlobalExceptionHandler.java
index e7c4ae4..eeda598 100644
--- a/exam-framework/src/main/java/com/gkhy/exam/framework/exception/GlobalExceptionHandler.java
+++ b/exam-framework/src/main/java/com/gkhy/exam/framework/exception/GlobalExceptionHandler.java
@@ -80,7 +80,7 @@
     public CommonResult handleRuntimeException(RuntimeException ex, HttpServletRequest request)
     {
         writeExceptionLogFile(ex);
-        return CommonResult.failed(ex.getMessage());
+        return CommonResult.failed("内部服务异常");
     }
 
     /**
diff --git a/exam-framework/src/main/java/com/gkhy/exam/framework/job/PaperStudentJob.java b/exam-framework/src/main/java/com/gkhy/exam/framework/job/PaperStudentJob.java
new file mode 100644
index 0000000..7e45fe8
--- /dev/null
+++ b/exam-framework/src/main/java/com/gkhy/exam/framework/job/PaperStudentJob.java
@@ -0,0 +1,70 @@
+package com.gkhy.exam.framework.job;
+
+import com.gkhy.exam.system.domain.ExPaperStudent;
+import com.gkhy.exam.system.mapper.ExPaperStudentMapper;
+import com.gkhy.exam.system.service.ExPaperStudentService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+import java.util.List;
+
+/**
+ * 考生考试超时处理job
+ */
+@Slf4j
+@Component
+public class PaperStudentJob {
+    @Autowired
+    private ExPaperStudentMapper paperStudentMapper;
+    @Autowired
+    private ExPaperStudentService paperStudentService;
+
+    /**
+     * 建议:每1小时秒执行一次
+     */
+    @Scheduled(cron = "0 */10 * * * ?")
+    public void doprogress() {
+        try {
+            int pageIndex = 1;
+            int pageSize = 20;
+            while (true) {
+                List<ExPaperStudent> paperStudentList = paperStudentMapper.selectNoCompleteStudent((pageIndex - 1) * pageSize, pageSize);
+                if (paperStudentList.isEmpty()) {
+                    break;
+                }
+                for (ExPaperStudent paperStudent : paperStudentList) {
+                    handle(paperStudent);
+                }
+                if (paperStudentList.size() < pageSize) {
+                    break;
+                }
+                pageIndex = pageIndex + 1;
+            }
+        }catch (Exception e){
+            log.error("PaperStudentJob doprogress error:{}",e.getMessage());
+        }
+    }
+
+    public void handle(ExPaperStudent pStudent){
+        Long currentDateTime = System.currentTimeMillis();
+        LocalDateTime deadline = pStudent.getExamPaper().getDeadline();
+        if (currentDateTime - deadline.toInstant(ZoneOffset.of("+8")).toEpochMilli() < 0) {
+            if(pStudent.getExamPaper().getLimited()==1){
+                if (pStudent.getStartTime() == null) {
+                    return;
+                }
+                if(currentDateTime - pStudent.getStartTime() < pStudent.getExamPaper().getLimitTime() * 60 * 1000) {
+                    return;
+                }
+            }else {
+                return;
+            }
+        }
+        paperStudentService.handlePaperData(pStudent);
+    }
+
+}
diff --git a/exam-framework/src/main/java/com/gkhy/exam/framework/job/UserStudyJob.java b/exam-framework/src/main/java/com/gkhy/exam/framework/job/UserStudyJob.java
index ab9202d..68ed589 100644
--- a/exam-framework/src/main/java/com/gkhy/exam/framework/job/UserStudyJob.java
+++ b/exam-framework/src/main/java/com/gkhy/exam/framework/job/UserStudyJob.java
@@ -8,6 +8,7 @@
 import com.gkhy.exam.system.domain.ExStudentStudy;
 import com.gkhy.exam.system.mapper.ExResourceMapper;
 import com.gkhy.exam.system.mapper.ExStudentStudyMapper;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;
@@ -18,6 +19,7 @@
 /**
  * 学习进度job
  */
+@Slf4j
 @Component
 public class UserStudyJob {
     @Autowired
@@ -31,22 +33,32 @@
      * 建议:每10秒执行一次
      */
     @Scheduled(cron = "*/10 * * * * ?")
-    public void progress(){
-        Set<String> keys = redisUtils.keys(CacheConstant.STUDY_PROCESS_KEY + "*");
-        if(ObjectUtil.isNotEmpty(keys)){
-            for(String key:keys){
-                ExStudentStudy studentStudy = (ExStudentStudy) redisUtils.get(key);
-                ExResource resource=resourceMapper.selectById(studentStudy.getResourceId());
-                if(ResourceTypeEnum.VIDEO.getCode().equals(resource.getResourceType())||ResourceTypeEnum.AUDIO.getCode().equals(resource.getResourceType())){
-                    studentStudy.setProgress(new BigDecimal(studentStudy.getCurrentDuration()).divide(new BigDecimal(resource.getResourceLength()),BigDecimal.ROUND_CEILING).multiply(BigDecimal.valueOf(100)));
-                }else{
-                    studentStudy.setProgress(BigDecimal.valueOf(studentStudy.getCurrentPage()).divide(BigDecimal.valueOf(resource.getDocPage()).multiply(BigDecimal.valueOf(100))));
-
+    public void doprogress(){
+        try {
+            Set<String> keys = redisUtils.keys(CacheConstant.STUDY_PROCESS_KEY + "*");
+            if (ObjectUtil.isNotEmpty(keys)) {
+                for (String key : keys) {
+                    ExStudentStudy studentStudy = (ExStudentStudy) redisUtils.get(key);
+                    ExResource resource = resourceMapper.selectById(studentStudy.getResourceId());
+                    if (ResourceTypeEnum.VIDEO.getCode().equals(resource.getResourceType()) || ResourceTypeEnum.AUDIO.getCode().equals(resource.getResourceType())) {
+                        studentStudy.setProgress(new BigDecimal(studentStudy.getCurrentDuration()).divide(new BigDecimal(resource.getResourceLength()), BigDecimal.ROUND_CEILING).multiply(BigDecimal.valueOf(100)));
+                    } else {
+                        studentStudy.setProgress(BigDecimal.valueOf(studentStudy.getCurrentPage()).divide(BigDecimal.valueOf(resource.getDocPage()).multiply(BigDecimal.valueOf(100))));
+                    }
+                    studentStudyMapper.updateById(studentStudy);
+                    redisUtils.del(key);
                 }
-                studentStudyMapper.updateById(studentStudy);
-                redisUtils.del(key);
             }
+        }catch (Exception e){
+            log.error("UserStudyJob doprogress error:{}",e.getMessage());
         }
 
     }
+
+    /**
+     * 统计学员学习总进度
+     */
+    public void staticProgress(){
+
+    }
 }
diff --git a/exam-framework/src/main/java/com/gkhy/exam/framework/security/SecurityConfig.java b/exam-framework/src/main/java/com/gkhy/exam/framework/security/SecurityConfig.java
index 98a3e29..b08e275 100644
--- a/exam-framework/src/main/java/com/gkhy/exam/framework/security/SecurityConfig.java
+++ b/exam-framework/src/main/java/com/gkhy/exam/framework/security/SecurityConfig.java
@@ -100,6 +100,7 @@
         permitAllUrl.getUrls().forEach(url -> registry.antMatchers(url).permitAll());
 
         httpSecurity
+                .cors().and()
                 // CSRF禁用,因为不使用session
                 .csrf().disable()
                 // 禁用HTTP响应标头
@@ -111,7 +112,7 @@
                 // 过滤请求
                 .authorizeRequests()
                 // 对于登录login 注册register 验证码captchaImage 允许匿名访问
-                .antMatchers("/**/login", "/register", "/system/captcha/captchaImage").permitAll()
+                .antMatchers("/**/login", "/register", "/system/captcha/captchaImage","/system/common/importExcel").permitAll()
                 // 静态资源,可匿名访问
                 .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**","/**/favicon.ico","/**/images/**").permitAll()
                 .antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()
@@ -128,6 +129,7 @@
         httpSecurity.addFilterBefore(corsFilter, LogoutFilter.class);
     }
 
+
     /**
      * 强散列哈希加密实现
      */
diff --git a/exam-framework/src/main/java/com/gkhy/exam/framework/security/handle/AuthenticationEntryPointImpl.java b/exam-framework/src/main/java/com/gkhy/exam/framework/security/handle/AuthenticationEntryPointImpl.java
index f3e7e66..90ead25 100644
--- a/exam-framework/src/main/java/com/gkhy/exam/framework/security/handle/AuthenticationEntryPointImpl.java
+++ b/exam-framework/src/main/java/com/gkhy/exam/framework/security/handle/AuthenticationEntryPointImpl.java
@@ -31,7 +31,7 @@
     {
         String msg = StringUtils.format("请求访问:{},认证失败,无法访问系统资源", request.getRequestURI());
         log.error(msg);
-        ServletUtils.renderString(response, JSON.toJSONString(CommonResult.failed(ResultCode.FORBIDDEN,msg)));
+        ServletUtils.renderString(response, JSON.toJSONString(CommonResult.failed(ResultCode.UNAUTHORIZED,msg)));
 
     }
 }
diff --git a/exam-framework/src/main/java/com/gkhy/exam/framework/web/service/SysLoginService.java b/exam-framework/src/main/java/com/gkhy/exam/framework/web/service/SysLoginService.java
index 5254764..bcde6f7 100644
--- a/exam-framework/src/main/java/com/gkhy/exam/framework/web/service/SysLoginService.java
+++ b/exam-framework/src/main/java/com/gkhy/exam/framework/web/service/SysLoginService.java
@@ -25,6 +25,7 @@
 import org.springframework.stereotype.Component;
 
 import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
 import java.time.LocalDateTime;
 
 @Component
@@ -39,6 +40,8 @@
     private TokenService tokenService;
     @Autowired
     private ExStudentService studentService;
+    @Autowired
+    private HttpServletRequest request;
 
 
 
@@ -87,18 +90,18 @@
             authentication = authenticationManager.authenticate(authenticationToken);
             LoginUserDetails loginUserDetails= (LoginUserDetails) authentication.getPrincipal();
             passwordService.validate(loginUserDetails.getUser(),password);
-            AsyncManager.me().execute(AsyncFactory.recordLoginInfo(username, Constant.LOGIN_SUCCESS, "登录成功"));
+        //    AsyncManager.me().execute(AsyncFactory.recordLoginInfo(username, Constant.LOGIN_SUCCESS, "登录成功"));
             recordLoginInfo(loginUserDetails.getUser().getId(),LoginUserTagEnum.ADMIN_USER);
             return createLoginUser(loginUserDetails,LoginUserTagEnum.ADMIN_USER);
         }catch (Exception e){
             if (e instanceof BadCredentialsException)
             {
-                AsyncManager.me().execute(AsyncFactory.recordLoginInfo(username, Constant.LOGIN_FAIL, "用户密码不匹配"));
+             //   AsyncManager.me().execute(AsyncFactory.recordLoginInfo(username, Constant.LOGIN_FAIL, "用户密码不匹配"));
                 throw new ApiException("用户密码不匹配");
             }
             else
             {
-                AsyncManager.me().execute(AsyncFactory.recordLoginInfo(username, Constant.LOGIN_FAIL, e.getMessage()));
+              //  AsyncManager.me().execute(AsyncFactory.recordLoginInfo(username, Constant.LOGIN_FAIL, e.getMessage()));
                 throw new ApiException(e.getMessage());
             }
         }finally {
@@ -125,18 +128,18 @@
             authentication = authenticationManager.authenticate(authenticationToken);
             LoginUserDetails loginUserDetails= (LoginUserDetails) authentication.getPrincipal();
             passwordService.validate(loginUserDetails.getUser(),password);
-            AsyncManager.me().execute(AsyncFactory.recordLoginInfo(username, Constant.LOGIN_SUCCESS, "登录成功"));
+        //    AsyncManager.me().execute(AsyncFactory.recordLoginInfo(username, Constant.LOGIN_SUCCESS, "登录成功"));
             recordLoginInfo(loginUserDetails.getUser().getId(),LoginUserTagEnum.STUDENT_USER);
             return createLoginUser(loginUserDetails,LoginUserTagEnum.STUDENT_USER);
         }catch (Exception e){
             if (e instanceof BadCredentialsException)
             {
-                AsyncManager.me().execute(AsyncFactory.recordLoginInfo(username, Constant.LOGIN_FAIL, "用户密码不匹配"));
+               // AsyncManager.me().execute(AsyncFactory.recordLoginInfo(username, Constant.LOGIN_FAIL, "用户密码不匹配"));
                 throw new ApiException("用户密码不匹配");
             }
             else
             {
-                AsyncManager.me().execute(AsyncFactory.recordLoginInfo(username, Constant.LOGIN_FAIL, e.getMessage()));
+               // AsyncManager.me().execute(AsyncFactory.recordLoginInfo(username, Constant.LOGIN_FAIL, e.getMessage()));
                 throw new ApiException(e.getMessage());
             }
         }finally {
@@ -193,6 +196,11 @@
     }
 
 
+    public void logout(){
+        tokenService.delTokenCache(request);
+    }
+
+
 
 
 }
diff --git a/exam-framework/src/main/java/com/gkhy/exam/framework/web/service/TokenService.java b/exam-framework/src/main/java/com/gkhy/exam/framework/web/service/TokenService.java
index 8cb3349..4a34050 100644
--- a/exam-framework/src/main/java/com/gkhy/exam/framework/web/service/TokenService.java
+++ b/exam-framework/src/main/java/com/gkhy/exam/framework/web/service/TokenService.java
@@ -1,12 +1,14 @@
 package com.gkhy.exam.framework.web.service;
 
 import cn.hutool.crypto.digest.DigestUtil;
+import com.gkhy.exam.common.api.ResultCode;
 import com.gkhy.exam.common.constant.CacheConstant;
 import com.gkhy.exam.common.domain.model.LoginUser;
 import com.gkhy.exam.common.exception.ApiException;
 import com.gkhy.exam.common.utils.RedisUtils;
 import com.gkhy.exam.common.utils.StringUtils;
 import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.ExpiredJwtException;
 import io.jsonwebtoken.Jwts;
 import io.jsonwebtoken.SignatureAlgorithm;
 import lombok.extern.slf4j.Slf4j;
@@ -101,16 +103,10 @@
      * 从token中获取JWT中的负载
      */
     private Claims getClaimsFromToken(String token) {
-        Claims claims = null;
-        try {
-            claims = Jwts.parser()
+        return Jwts.parser()
                     .setSigningKey(SECRET)
                     .parseClaimsJws(token)
                     .getBody();
-        } catch (Exception e) {
-            log.error("JWT格式验证失败:{}", token);
-        }
-        return claims;
     }
 
     /**
@@ -121,8 +117,9 @@
         try {
             Claims claims = getClaimsFromToken(token);
             username = claims.getSubject();
-        } catch (Exception e) {
-            username = null;
+        } catch (ExpiredJwtException e) {
+            log.error("JWT过期:{}", token);
+            throw new ApiException(ResultCode.UNAUTHORIZED);
         }
         return username;
     }
@@ -146,13 +143,13 @@
         String tagUsername = getUserNameFromToken(token);
         String username=tagUsername.substring(0,tagUsername.lastIndexOf("_"));
         if(StringUtils.isBlank(username)||!username.equals(userDetails.getUsername())){
-            return false;
+            throw new ApiException(ResultCode.UNAUTHORIZED);
         }
         String tokenKey=redisUtils.generateKey(CacheConstant.SYS_USER_TOKEN+md5Encode(token));
         String userKey=redisUtils.generateKey(CacheConstant.SYS_USER_TOKEN+username);
         String cacheToken= (String) redisUtils.get(tokenKey);
         if(StringUtils.isBlank(cacheToken)||isTokenExpired(cacheToken)){
-            return false;
+            throw new ApiException(ResultCode.UNAUTHORIZED);
         }
         if(isNeedUpdate(cacheToken)){
             String newToken=createToken(tagUsername);
@@ -162,6 +159,7 @@
         }
         return true;
     }
+
 
 
 
@@ -248,4 +246,17 @@
 
 
 
+    public void delTokenCache(HttpServletRequest request){
+        String token=getToken(request);
+        String tokenKey=redisUtils.generateKey(CacheConstant.SYS_USER_TOKEN+md5Encode(token));
+        redisUtils.del(tokenKey);
+        String tagUsername = getUserNameFromToken(token);
+        String username=tagUsername.substring(0,tagUsername.lastIndexOf("_"));
+        if(!StringUtils.isBlank(username)){
+            String userKey=redisUtils.generateKey(CacheConstant.SYS_USER_TOKEN+username);
+            redisUtils.del(userKey);
+        }
+    }
+
+
 }
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/domain/ExCompanyPeriod.java b/exam-system/src/main/java/com/gkhy/exam/system/domain/ExCompanyPeriod.java
index 58753a5..7340414 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/domain/ExCompanyPeriod.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/domain/ExCompanyPeriod.java
@@ -48,13 +48,13 @@
     @TableField("origin")
     private String origin;
 
-    @ApiModelProperty("变动情况(增减课时)")
+    @ApiModelProperty("变动情况(增减课时)秒")
     @TableField("modify_period")
-    private Integer modifyPeriod;
+    private Long modifyPeriod;
 
-    @ApiModelProperty("变动后剩余(分)")
+    @ApiModelProperty("变动后剩余(秒)")
     @TableField("remain_period")
-    private Integer remainPeriod;
+    private Long remainPeriod;
 
     @ApiModelProperty("创建时间")
     @TableField("create_time")
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/domain/ExCourse.java b/exam-system/src/main/java/com/gkhy/exam/system/domain/ExCourse.java
index 4af1e64..0c993d9 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/domain/ExCourse.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/domain/ExCourse.java
@@ -13,7 +13,6 @@
 import lombok.experimental.Accessors;
 import org.hibernate.validator.constraints.Length;
 
-import javax.validation.constraints.Min;
 import javax.validation.constraints.NotBlank;
 import javax.validation.constraints.NotNull;
 
@@ -68,11 +67,10 @@
     @TableField("introduce")
     private String introduce;
 
-    @ApiModelProperty("审批状态(0创建,1待审核,2审批通过,3审批不通过  默认0)")
+    @ApiModelProperty("审批状态(0待提交,1待审核,2审批通过,3审批不通过  默认0)")
     @TableField("state")
     private Integer state;
 
-    @NotNull(message = "提交公司id不能为空")
     @ApiModelProperty(value = "提交公司id",required = true)
     @TableField("company_id")
     private Long companyId;
@@ -81,11 +79,10 @@
     @TableField("privatize")
     private Integer privatize;
 
-    @NotNull(message = "要求课时不能为空")
-    @ApiModelProperty(value = "要求课时(秒)",required = true)
-    @Min(value = 0,message = "课时格式不正确")
-    @TableField("period")
-    private Long period;
+    @Length(min = 0, max = 50, message = "审批意见不能超过50个字符")
+    @ApiModelProperty("审批意见")
+    @TableField("message")
+    private String message;
 
 
     @ApiModelProperty("乐观锁")
@@ -106,4 +103,9 @@
     private String categoryName;
 
 
+    @ApiModelProperty(value = "要求课时(秒) 所有小结总和")
+    @TableField(exist = false)
+    private Long period;
+
+
 }
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/domain/ExCoursePhase.java b/exam-system/src/main/java/com/gkhy/exam/system/domain/ExCoursePhase.java
index 988fb73..50d091f 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/domain/ExCoursePhase.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/domain/ExCoursePhase.java
@@ -92,7 +92,23 @@
 
     @ApiModelProperty("课程课时")
     @TableField(exist = false)
-    private Integer coursePeriod;
+    private Long coursePeriod;
+
+    @ApiModelProperty("课程名称")
+    @TableField(exist = false)
+    private String courseName;
+
+    @ApiModelProperty("学员人数")
+    @TableField(exist = false)
+    private Integer studentCount;
+
+    @ApiModelProperty("公司名称")
+    @TableField(exist = false)
+    private String companyName;
+
+    @ApiModelProperty("完成人数")
+    @TableField(exist = false)
+    private Integer finishCount;
 
 
 }
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/domain/ExExamPaper.java b/exam-system/src/main/java/com/gkhy/exam/system/domain/ExExamPaper.java
index 62cca8b..0399f30 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/domain/ExExamPaper.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/domain/ExExamPaper.java
@@ -2,6 +2,7 @@
 
 import com.baomidou.mybatisplus.annotation.*;
 import com.fasterxml.jackson.annotation.JsonInclude;
+import com.gkhy.exam.system.domain.vo.PaperStudentInfoVO;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Getter;
@@ -69,80 +70,106 @@
     private Integer limitTime;
 
     @ApiModelProperty("是否限制考试时间(0否,1是,默认0)")
-    @TableField("limit")
-    private Integer limit;
+    @TableField("limited")
+    private Integer limited;
 
-    @NotNull(message = "单选题目数量不能为空")
-    @Min(value = 1,message = "单选题目数量必须大于0")
+//    @NotNull(message = "单选题目数量不能为空")
+//    @Min(value = 1,message = "单选题目数量必须大于0")
     @ApiModelProperty(value = "单选题目数量",required = true)
     @TableField("single_num")
     private Integer singleNum;
 
-    @NotNull(message = "单选题每题分数不能为空")
-    @Min(value = 1,message = "单选题每题分数必须大于0")
+//    @NotNull(message = "单选题每题分数不能为空")
+//    @Min(value = 1,message = "单选题每题分数必须大于0")
     @ApiModelProperty(value = "单选题每题分数",required = true)
     @TableField("single_score")
     private Integer singleScore;
 
-    @NotNull(message = "单选题题库不能为空")
+   // @NotNull(message = "单选题题库不能为空")
     @ApiModelProperty(value = "单选题题库id",required = true)
     @TableField("single_bank_id")
     private Long singleBankId;
 
-    @NotNull(message = "单选题出题方式不能为空")
+  //  @NotNull(message = "单选题出题方式不能为空")
     @ApiModelProperty(value = "单选题出题方式1随机,2顺序,默认1",required = true)
     @TableField("single_method")
     private Integer singleMethod;
 
-    @NotNull(message = "多选题目数量不能为空")
-    @Min(value = 1,message = "多选题目数量必须大于0")
+  //  @NotNull(message = "多选题目数量不能为空")
+  //  @Min(value = 1,message = "多选题目数量必须大于0")
     @ApiModelProperty(value = "多选题目数量",required = true)
     @TableField("multi_num")
     private Integer multiNum;
 
-    @NotNull(message = "多选题每题分数不能为空")
-    @Min(value = 1,message = "多选题每题分数必须大于0")
+ //   @NotNull(message = "多选题每题分数不能为空")
+ //   @Min(value = 1,message = "多选题每题分数必须大于0")
     @ApiModelProperty(value = "多选题每题分数",required = true)
     @TableField("multi_score")
     private Integer multiScore;
 
-    @NotNull(message = "多选题题库不能为空")
+   // @NotNull(message = "多选题题库不能为空")
     @ApiModelProperty(value = "多选题题库id",required = true)
     @TableField("multi_bank_id")
     private Long multiBankId;
 
-    @NotNull(message = "多选题出题方式不能为空")
+  //  @NotNull(message = "多选题出题方式不能为空")
     @ApiModelProperty(value = "多选题出题方式1随机,2顺序,默认1",required = true)
     @TableField("multi_method")
     private Integer multiMethod;
 
-    @NotNull(message = "判断题目数量不能为空")
-    @Min(value = 1,message = "判断题目数量必须大于0")
+ //   @NotNull(message = "判断题目数量不能为空")
+ //   @Min(value = 1,message = "判断题目数量必须大于0")
     @ApiModelProperty(value = "判断题目数量",required = true)
     @TableField("judge_num")
     private Integer judgeNum;
 
-    @NotNull(message = "判断题每题分数不能为空")
-    @Min(value = 1,message = "判断题每题分数必须大于0")
+//    @NotNull(message = "判断题每题分数不能为空")
+ //   @Min(value = 1,message = "判断题每题分数必须大于0")
     @ApiModelProperty(value = "判断题每题分数",required = true)
     @TableField("judge_score")
     private Integer judgeScore;
 
-    @NotNull(message = "判断题题库不能为空")
+  //  @NotNull(message = "判断题题库不能为空")
     @ApiModelProperty(value = "判断题题库id",required = true)
     @TableField("judge_bank_id")
     private Long judgeBankId;
 
-    @NotNull(message = "判断题出题方式不能为空")
+ //   @NotNull(message = "判断题出题方式不能为空")
     @ApiModelProperty(value = "判断题出题方式1随机,2顺序,默认1",required = true)
     @TableField("judge_method")
     private Integer judgeMethod;
+
+    @ApiModelProperty(value = "简答题题目数量",required = true)
+    @TableField("easy_num")
+    private Integer easyNum;
+
+//    @NotNull(message = "简答题每题分数不能为空")
+ //   @Min(value = 1,message = "简答题每题分数必须大于0")
+    @ApiModelProperty(value = "简答题每题分数",required = true)
+    @TableField("easy_score")
+    private Integer easyScore;
+
+//    @NotNull(message = "简答题题库不能为空")
+    @ApiModelProperty(value = "简答题题库id",required = true)
+    @TableField("easy_bank_id")
+    private Long easyBankId;
+
+ //   @NotNull(message = "简答题出题方式不能为空")
+    @ApiModelProperty(value = "简答题出题方式1随机,2顺序,默认1",required = true)
+    @TableField("easy_method")
+    private Integer easyMethod;
+
 
     @NotNull(message = "合格分数不能为空")
     @Min(value = 1,message = "合格分数必须大于0")
     @ApiModelProperty(value = "合格分数",required = true)
     @TableField("pass_score")
     private Integer passScore;
+
+    @NotNull(message = "考试截止时间不能为空")
+    @ApiModelProperty("考试截止时间")
+    @TableField("deadline")
+    private LocalDateTime deadline;
 
     @ApiModelProperty("创建时间")
     @TableField("create_time")
@@ -183,26 +210,40 @@
 
     @ApiModelProperty("单选题是否重新出题,0否 1是(编辑时传参)")
     @TableField(exist = false)
-    private Integer singleRebuild;
+    private Integer singleRebuild=0;
 
     @ApiModelProperty("多选题是否重新出题,0否 1是(编辑时传参)")
     @TableField(exist = false)
-    private Integer multiRebuild;
+    private Integer multiRebuild=0;
 
     @ApiModelProperty("判断题是否重新出题,0否 1是(编辑时传参)")
     @TableField(exist = false)
-    private Integer judgeRebuild;
+    private Integer judgeRebuild=0;
 
-    @ApiModelProperty("单选题列表")
+    @ApiModelProperty("简答题是否重新出题,0否 1是(编辑时传参)")
     @TableField(exist = false)
-    private List<ExQuestion> singleQuestions;
+    private Integer easyRebuild=0;
 
-    @ApiModelProperty("多选题列表")
+    @ApiModelProperty("题目列表")
     @TableField(exist = false)
-    private List<ExQuestion> multiQuestions;
+    private List<ExQuestion> questions;
 
-    @ApiModelProperty("判断题列表")
+    @ApiModelProperty("学员统计信息")
     @TableField(exist = false)
-    private List<ExQuestion> judgeQuestions;
+    private PaperStudentInfoVO paperStudentInfoVO;
+
+    @ApiModelProperty("单选题题库名称")
+    @TableField(exist = false)
+    private String singleBankName;
+    @ApiModelProperty("多选题题库名称")
+    @TableField(exist = false)
+    private String multiBankName;
+    @ApiModelProperty("判断题题库名称")
+    @TableField(exist = false)
+    private String judgeBankName;
+    @ApiModelProperty("简答题题库名称")
+    @TableField(exist = false)
+    private String easyBankName;
+
 
 }
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
index 280ce14..24d0bb4 100644
--- 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
@@ -4,13 +4,18 @@
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonInclude;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Getter;
 import lombok.Setter;
 
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
 import java.io.Serializable;
 import java.time.LocalDateTime;
+
+import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL;
 
 /**
  * <p>
@@ -24,6 +29,7 @@
 @Setter
 @TableName("ex_exam_record")
 @ApiModel(value = "ExExamRecord对象", description = "线下教育登记表")
+@JsonInclude(NON_NULL)
 public class ExExamRecord implements Serializable {
 
     private static final long serialVersionUID = 1L;
@@ -36,34 +42,42 @@
     @TableField("company_id")
     private Long companyId;
 
-    @ApiModelProperty("学员id")
+    @NotNull(message = "学员id不能为空")
+    @ApiModelProperty(value = "学员id",required = true)
     @TableField("student_id")
     private Long studentId;
 
-    @ApiModelProperty("计划名称")
+    @NotBlank(message = "计划名称不能为空")
+    @ApiModelProperty(value = "计划名称",required = true)
     @TableField("plan_name")
     private String planName;
 
-    @ApiModelProperty("课程名称")
+    @NotBlank(message = "课程名称不能为空")
+    @ApiModelProperty(value = "课程名称",required = true)
     @TableField("course_name")
     private String courseName;
 
-    @ApiModelProperty("培训等级")
+    @NotNull(message = "培训等级不能为空")
+    @ApiModelProperty(value = "培训等级(1公司级 2部门级 3车间级 默认1)",required = true)
     @TableField("level")
-    private String level;
+    private Integer level;
 
-    @ApiModelProperty("要求课时(分)")
+    @NotNull(message = "要求课时不能为空")
+    @ApiModelProperty(value = "要求课时(分)",required = true)
     @TableField("period")
     private Integer period;
 
-    @ApiModelProperty("实际课时(分)")
+    @NotNull(message = "实际课时不能为空")
+    @ApiModelProperty(value = "实际课时(分)",required = true)
     @TableField("actual_period")
     private Integer actualPeriod;
 
+    @NotNull(message = "考试成绩不能为空")
     @ApiModelProperty("考试成绩")
     @TableField("score")
     private Integer score;
 
+    @NotNull(message = "是否合格不能为空")
     @ApiModelProperty("是否合格,0不合格 1合格 默认0")
     @TableField("passed")
     private Integer passed;
@@ -93,5 +107,9 @@
     @TableField(exist = false)
     private String companyName;
 
+    @ApiModelProperty("学生对象")
+    @TableField(exist = false)
+    private ExStudent student;
+
 
 }
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/domain/ExExerciseAnswer.java b/exam-system/src/main/java/com/gkhy/exam/system/domain/ExExerciseAnswer.java
index ff38c5f..687b3b1 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/domain/ExExerciseAnswer.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/domain/ExExerciseAnswer.java
@@ -1,6 +1,7 @@
 package com.gkhy.exam.system.domain;
 
 import com.baomidou.mybatisplus.annotation.*;
+import com.fasterxml.jackson.annotation.JsonInclude;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Getter;
@@ -10,6 +11,8 @@
 import javax.validation.constraints.NotNull;
 import java.io.Serializable;
 import java.time.LocalDateTime;
+
+import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL;
 
 /**
  * <p>
@@ -23,6 +26,7 @@
 @Setter
 @TableName("ex_exercise_answer")
 @ApiModel(value = "ExExerciseAnswer对象", description = "学员与练习题关系表")
+@JsonInclude(NON_NULL)
 public class ExExerciseAnswer implements Serializable {
 
     private static final long serialVersionUID = 1L;
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/domain/ExPaperStudent.java b/exam-system/src/main/java/com/gkhy/exam/system/domain/ExPaperStudent.java
index 32750b6..9face33 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/domain/ExPaperStudent.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/domain/ExPaperStudent.java
@@ -29,7 +29,7 @@
 @TableName("ex_paper_student")
 @ApiModel(value = "ExPaperStudent对象", description = "学员与考试题目关系表")
 @JsonInclude(NON_NULL)
-public class ExPaperStudent implements Serializable {
+public class ExPaperStudent  implements Serializable {
 
     private static final long serialVersionUID = 1L;
 
@@ -55,9 +55,9 @@
     @TableField("passed")
     private Integer passed;
 
-    @ApiModelProperty("是否完成考试(0否,1是 默认0)")
-    @TableField("completed")
-    private Integer completed;
+//    @ApiModelProperty("是否完成考试(0否,1是 默认0)")
+//    @TableField("completed")
+//    private Integer completed;
 
     @ApiModelProperty("考试时长(分钟)")
     @TableField("use_time")
@@ -70,6 +70,10 @@
     @ApiModelProperty("考试结束时间(时间戳13位ms)")
     @TableField("end_time")
     private Long endTime;
+
+    @ApiModelProperty("状态:0待考试,1待批阅 2批阅完成,默认0")
+    @TableField("state")
+    private Integer state;
 
     @ApiModelProperty("创建时间")
     @TableField("create_time")
@@ -100,17 +104,25 @@
     @TableField("create_id")
     private Long createId;
 
-    @ApiModelProperty(value = "学生名称",required = true)
+    @ApiModelProperty(value = "学生名称")
     @TableField(exist = false)
     private String studentName;
 
-    @ApiModelProperty(value = "学生手机号",required = true)
+    @ApiModelProperty(value = "学生手机号")
     @TableField(exist = false)
     private String studentPhone;
 
-    @ApiModelProperty(value = "分配人名称",required = true)
+    @ApiModelProperty(value = "分配人名称")
     @TableField(exist = false)
     private String createName;
+
+    @ApiModelProperty(value = "公司id")
+    @TableField(exist = false)
+    private Long companyId;
+
+    @ApiModelProperty(value = "公司名称")
+    @TableField(exist = false)
+    private String companyName;
 
     @ApiModelProperty("试卷对象")
     @TableField(exist = false)
@@ -120,16 +132,10 @@
     @TableField(exist = false)
     private ExStudent student;
 
-    @ApiModelProperty("单选题列表")
-    @TableField(exist = false)
-    private List<ExQuestion> singleQuestions;
 
-    @ApiModelProperty("多选题列表")
+    @ApiModelProperty("题目列表")
     @TableField(exist = false)
-    private List<ExQuestion> multiQuestions;
+    private List<ExQuestion> questions;
 
-    @ApiModelProperty("判断题列表")
-    @TableField(exist = false)
-    private List<ExQuestion> judgeQuestions;
 
 }
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/domain/ExPhaseStudent.java b/exam-system/src/main/java/com/gkhy/exam/system/domain/ExPhaseStudent.java
index b3b01e9..96a07b7 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/domain/ExPhaseStudent.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/domain/ExPhaseStudent.java
@@ -80,12 +80,17 @@
     @TableField(exist = false)
     private String createName;
 
-    @ApiModelProperty("课时")
-    @TableField(exist = false)
-    private Integer period;
-
     @ApiModelProperty("课程对象")
     @TableField(exist = false)
     private ExCourse course;
 
+
+    @ApiModelProperty("企业id")
+    @TableField(exist = false)
+    private Long companyId;
+
+    @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 81e1b50..291719a 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
@@ -39,7 +39,7 @@
     @TableId(value = "id", type = IdType.AUTO)
     private Long id;
     @NotNull(message = "考题类型不能为空")
-    @ApiModelProperty(value = "考题类型(1单选题,2多选题,3判断题 默认1)",required = true)
+    @ApiModelProperty(value = "考题类型(1单选题,2多选题,3判断题,4简单题 默认1)",required = true)
     @TableField("question_type")
     private Integer questionType;
 
@@ -48,7 +48,7 @@
     @TableField("bank_id")
     private Long bankId;
 
-    @NotNull(message = "公司id不能为空")
+
     @ApiModelProperty("公司id")
     @TableField("company_id")
     private Long companyId;
@@ -57,7 +57,7 @@
     @TableField("status")
     private Integer status;
 
-    @NotBlank(message = "答案不能为空")
+    @NotBlank(message = "答案不能为空(判断题对传1,错误0)")
     @ApiModelProperty(value = "答案",required = true)
     @TableField("answer")
     private String answer;
@@ -75,7 +75,8 @@
     /**
      * json格式:
      * 单选和多选   {"analyze":"",items:[{"prefix":"A","content":"xxxx"},{"prefix":"B","content":"xxxx"},{"prefix":"C","content":"xxxx"},{"prefix":"D","content":"xxxx"}]}
-     * 判断题   {"analyze":""}
+     * 判断题   {"analyze":"",items[{"prefix":"A","content":"是"},{"prefix":"B","content":"否"}]}
+     * 简答题   {"analyze":""}
      */
     @ApiModelProperty("题目内容(json字符串)")
     @TableField("content")
@@ -114,6 +115,10 @@
     @TableField(exist = false)
     private ExExerciseAnswer exExerciseAnswer;
 
+    @ApiModelProperty("题库名称")
+    @TableField(exist = false)
+    private String bankName;
+
 
 
 }
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/domain/ExQuestionBank.java b/exam-system/src/main/java/com/gkhy/exam/system/domain/ExQuestionBank.java
index 60da83c..784d94b 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/domain/ExQuestionBank.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/domain/ExQuestionBank.java
@@ -92,12 +92,32 @@
     @TableField(exist = false)
     private Long studentId;
 
-    @ApiModelProperty("题目数量")
+    @ApiModelProperty("题目总数量")
     @TableField(exist = false)
     private Integer totalCount;
+
+    @ApiModelProperty("单选题数量")
+    @TableField(exist = false)
+    private Integer singleCount;
+
+    @ApiModelProperty("多选题数量")
+    @TableField(exist = false)
+    private Integer multiCount;
+
+    @ApiModelProperty("判断题数量")
+    @TableField(exist = false)
+    private Integer judgeCount;
 
     @ApiModelProperty("学员练习数量")
     @TableField(exist = false)
     private Integer exerciseCount;
 
+    @ApiModelProperty("分类名称")
+    @TableField(exist = false)
+    private String categoryName;
+
+    @ApiModelProperty("最新刷题的题目id")
+    @TableField(exist = false)
+    private Long questionId;
+
 }
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/domain/ExStudent.java b/exam-system/src/main/java/com/gkhy/exam/system/domain/ExStudent.java
index bffdd1c..980d053 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/domain/ExStudent.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/domain/ExStudent.java
@@ -5,6 +5,10 @@
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.fasterxml.jackson.annotation.JsonInclude;
+import com.gkhy.exam.common.annotation.DataDesensitizationType;
+import com.gkhy.exam.common.domain.BaseEntity;
+import com.gkhy.exam.common.domain.entity.SysUser;
+import com.gkhy.exam.common.enums.SensitiveTypeEnum;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Getter;
@@ -15,7 +19,6 @@
 import javax.validation.constraints.NotBlank;
 import javax.validation.constraints.NotNull;
 import javax.validation.constraints.Pattern;
-import java.io.Serializable;
 import java.time.LocalDateTime;
 
 import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL;
@@ -34,7 +37,7 @@
 @Accessors(chain = true)
 @ApiModel(value = "ExStudent对象", description = "学员表")
 @JsonInclude(NON_NULL)
-public class ExStudent implements Serializable {
+public class ExStudent extends BaseEntity {
 
     private static final long serialVersionUID = 1L;
 
@@ -75,6 +78,7 @@
     @TableField("phone")
     private String phone;
 
+    @DataDesensitizationType(type = SensitiveTypeEnum.ID_CARD)
     @NotBlank(message = "身份证号不能为空")
     @Length(min = 18, max = 18, message = "身份证号只能为18位")
     @ApiModelProperty(value = "身份证号",required = true)
@@ -97,26 +101,6 @@
     @TableField("create_id")
     private Long createId;
 
-    @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("version")
     private Integer version;
@@ -137,5 +121,9 @@
     @TableField(exist = false)
     private SysCompany company;
 
+    @ApiModelProperty("创建人信息")
+    @TableField(exist = false)
+    private SysUser createUser;
+
 
 }
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/domain/ExStudentAnswer.java b/exam-system/src/main/java/com/gkhy/exam/system/domain/ExStudentAnswer.java
index a937771..655f34d 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/domain/ExStudentAnswer.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/domain/ExStudentAnswer.java
@@ -58,7 +58,11 @@
     @TableField("answer")
     private String answer;
 
-    @ApiModelProperty("是否正确(0错误,1正确)")
+    @ApiModelProperty("得分")
+    @TableField("score")
+    private Integer score;
+
+    @ApiModelProperty("是否正确(0错误,1正确,2待批改)")
     @TableField("passed")
     private Integer passed;
 
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/domain/ExStudentStudy.java b/exam-system/src/main/java/com/gkhy/exam/system/domain/ExStudentStudy.java
index 4a1ea34..9bb0f05 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/domain/ExStudentStudy.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/domain/ExStudentStudy.java
@@ -72,9 +72,6 @@
     @TableField("progress")
     private BigDecimal progress;
 
-    @ApiModelProperty("资源类型(PPT,MP4,PDF)")
-    @TableField("resource_type")
-    private String resourceType;
 
     @ApiModelProperty("创建时间")
     @TableField("create_time")
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/domain/SysCategory.java b/exam-system/src/main/java/com/gkhy/exam/system/domain/SysCategory.java
index 6cc9384..e5df411 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/domain/SysCategory.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/domain/SysCategory.java
@@ -46,6 +46,10 @@
     @TableField("name")
     private String name;
 
+    @ApiModelProperty("删除标志,0未删除,1删除,默认0")
+    @TableField("del_flag")
+    private Integer delFlag;
+
 //    @ApiModelProperty("类型(1课程,2资源)")
 //    @TableField("category_type")
 //    private Integer categoryType;
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/domain/SysCompany.java b/exam-system/src/main/java/com/gkhy/exam/system/domain/SysCompany.java
index f84c302..69492df 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/domain/SysCompany.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/domain/SysCompany.java
@@ -10,6 +10,7 @@
 import lombok.experimental.Accessors;
 import org.hibernate.validator.constraints.Length;
 
+import javax.validation.constraints.Max;
 import javax.validation.constraints.NotBlank;
 import javax.validation.constraints.NotNull;
 import javax.validation.constraints.Pattern;
@@ -61,21 +62,19 @@
     private String phone;
 
     @ApiModelProperty("删除标志,0未删除,1删除,默认0")
-    @TableField("delFlag")
+    @TableField("del_flag")
     private Integer delFlag;
 
-    @ApiModelProperty("剩余课时(分)")
+    @ApiModelProperty("剩余课时(秒)")
     @TableField("remain_period")
-    private Integer remainPeriod;
+    private Long remainPeriod;
 
-    @ApiModelProperty("已用课时(分)")
-    @TableField("spend_period")
-    private Integer spendPeriod;
 
     @NotNull(message = "总课时不能为空")
-    @ApiModelProperty(value = "总课时(分)",required = true)
+    @Max(value = 9999999999L,message = "总课时长度不能超过10位")
+    @ApiModelProperty(value = "总课时(秒)",required = true)
     @TableField("total_period")
-    private Integer totalPeriod;
+    private Long totalPeriod;
 
     @Version
     @ApiModelProperty("乐观锁")
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/domain/vo/BatchPaperStudentVO.java b/exam-system/src/main/java/com/gkhy/exam/system/domain/vo/BatchPaperStudentVO.java
new file mode 100644
index 0000000..4f66eb6
--- /dev/null
+++ b/exam-system/src/main/java/com/gkhy/exam/system/domain/vo/BatchPaperStudentVO.java
@@ -0,0 +1,29 @@
+package com.gkhy.exam.system.domain.vo;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL;
+
+@Getter
+@Setter
+@Accessors(chain = true)  //链式写法
+@ApiModel(value = "试卷批量绑定学员对象", description = "试卷批量绑定学员对象")
+@JsonInclude(NON_NULL)
+public class BatchPaperStudentVO {
+    @ApiModelProperty("批次id列表")
+    private List<Long> phaseIds;
+    @ApiModelProperty("学员id列表")
+    private List<Long> studentIds;
+
+    @NotNull(message = "考卷id不能为空")
+    @ApiModelProperty(value = "考卷id",required = true)
+    private Long paperId;
+}
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
index f0b7373..5a4236f 100644
--- 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
@@ -1,13 +1,17 @@
 package com.gkhy.exam.system.domain.vo;
 
+import com.fasterxml.jackson.annotation.JsonInclude;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Getter;
 import lombok.Setter;
 import lombok.experimental.Accessors;
 
+import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL;
+
 @Getter
 @Setter
 @Accessors(chain = true)
+@JsonInclude(NON_NULL)
 public class CompanyPaperStudentVO {
     @ApiModelProperty("公司id")
     private Long companyId;
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
index 87e0e5e..ea3045f 100644
--- 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
@@ -1,13 +1,17 @@
 package com.gkhy.exam.system.domain.vo;
 
+import com.fasterxml.jackson.annotation.JsonInclude;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Getter;
 import lombok.Setter;
 import lombok.experimental.Accessors;
 
+import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL;
+
 @Getter
 @Setter
 @Accessors(chain = true)
+@JsonInclude(NON_NULL)
 public class CompanyPhaseStudentVO {
     @ApiModelProperty("公司id")
     private Long companyId;
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
index 2346a78..ea925ff 100644
--- 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
@@ -1,13 +1,19 @@
 package com.gkhy.exam.system.domain.vo;
 
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Getter;
 import lombok.Setter;
 import lombok.experimental.Accessors;
 
+import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL;
+
 @Getter
 @Setter
 @Accessors(chain = true)
+@ApiModel(value = "CompanyPhaseVO对象", description = "公司批次统计对象")
+@JsonInclude(NON_NULL)
 public class CompanyPhaseVO {
     @ApiModelProperty("公司id")
     private Long companyId;
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
index 7d221c3..fffeb72 100644
--- 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
@@ -1,15 +1,19 @@
 package com.gkhy.exam.system.domain.vo;
 
+import com.fasterxml.jackson.annotation.JsonInclude;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Getter;
 import lombok.Setter;
 import lombok.experimental.Accessors;
 
+import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL;
+
 @Getter
 @Setter
 @Accessors(chain = true)
 @ApiModel(value = "CompanyStatisticVO对象", description = "公司数据统计对象")
+@JsonInclude(NON_NULL)
 public class CompanyStatisticVO {
     @ApiModelProperty("公司id")
     private Long companyId;
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/domain/vo/ExPaperStudentVO.java b/exam-system/src/main/java/com/gkhy/exam/system/domain/vo/ExPaperStudentVO.java
new file mode 100644
index 0000000..2aba813
--- /dev/null
+++ b/exam-system/src/main/java/com/gkhy/exam/system/domain/vo/ExPaperStudentVO.java
@@ -0,0 +1,60 @@
+package com.gkhy.exam.system.domain.vo;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL;
+
+
+@Getter
+@Setter
+@Accessors(chain = true)
+@ApiModel(value = "ExPaperStudent对象", description = "学员与考试题目关系表")
+@JsonInclude(NON_NULL)
+public class ExPaperStudentVO{
+
+    @NotNull(message = "学员与试卷关系id")
+    @ApiModelProperty(value = "学员与试卷关系id",required = true)
+    private Long id;
+
+    @NotNull(message = "考卷id不能为空")
+    @ApiModelProperty(value = "考卷id",required = true)
+    private Long paperId;
+
+    @NotNull(message = "学员id不能为空")
+    @ApiModelProperty(value = "学员id",required = true)
+    private Long studentId;
+
+    @NotNull(message = "简答题题目列表不能为空")
+    @ApiModelProperty("题目列表")
+    private List<QuestionVO> questions;
+
+    @Getter
+    @Setter
+    @NoArgsConstructor
+    public static class QuestionVO {
+        @NotNull(message = "题目id不能为空")
+        @ApiModelProperty(value = "题目id",required = true)
+        private Long questionId;
+
+        @NotNull(message = "得分不能为空")
+        @ApiModelProperty("得分")
+        private Integer score;
+
+        @NotNull(message = "题目分数不能为空")
+        @ApiModelProperty("题目分数")
+        private Integer questionScore;
+
+    }
+
+}
+
+
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/domain/vo/PaperStudentInfoVO.java b/exam-system/src/main/java/com/gkhy/exam/system/domain/vo/PaperStudentInfoVO.java
new file mode 100644
index 0000000..13844f8
--- /dev/null
+++ b/exam-system/src/main/java/com/gkhy/exam/system/domain/vo/PaperStudentInfoVO.java
@@ -0,0 +1,34 @@
+package com.gkhy.exam.system.domain.vo;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+
+import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL;
+
+@Getter
+@Setter
+@Accessors(chain = true)  //链式写法
+@ApiModel(value = "试卷学员统计信息对象", description = "试卷学员统计信息对象")
+@JsonInclude(NON_NULL)
+public class PaperStudentInfoVO {
+    @ApiModelProperty("学员人数")
+    @TableField(exist = false)
+    private Integer studentCount;
+
+    @ApiModelProperty("合格人数")
+    @TableField(exist = false)
+    private Integer passStudentCount;
+
+    @ApiModelProperty("平均分数")
+    @TableField(exist = false)
+    private String avgScore;
+
+    @ApiModelProperty("完成人数")
+    @TableField(exist = false)
+    private Integer finishCount;
+}
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/domain/vo/StudentStudyPeriodVO.java b/exam-system/src/main/java/com/gkhy/exam/system/domain/vo/StudentStudyPeriodVO.java
index 0c7d62b..0b6e742 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/domain/vo/StudentStudyPeriodVO.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/domain/vo/StudentStudyPeriodVO.java
@@ -1,5 +1,6 @@
 package com.gkhy.exam.system.domain.vo;
 
+import com.fasterxml.jackson.annotation.JsonInclude;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Getter;
@@ -9,10 +10,13 @@
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
 
+import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL;
+
 @Getter
 @Setter
 @Accessors(chain = true)
 @ApiModel(description = "课程用户学习日志")
+@JsonInclude(NON_NULL)
 public class StudentStudyPeriodVO {
     @ApiModelProperty(value = "课时id")
     private Long periodId;
@@ -37,4 +41,8 @@
 
     @ApiModelProperty(value = "资源id")
     private Long resourceId;
+
+    @ApiModelProperty(value = "资源种类(1:视频2:音频;3:文档)")
+    private Integer resourceType;
+
 }
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/domain/vo/StudentStudyVO.java b/exam-system/src/main/java/com/gkhy/exam/system/domain/vo/StudentStudyVO.java
index a1a7c25..58740a5 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/domain/vo/StudentStudyVO.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/domain/vo/StudentStudyVO.java
@@ -1,5 +1,6 @@
 package com.gkhy.exam.system.domain.vo;
 
+import com.fasterxml.jackson.annotation.JsonInclude;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Getter;
@@ -9,10 +10,13 @@
 import java.io.Serializable;
 import java.util.List;
 
+import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL;
+
 @Setter
 @Getter
 @Accessors(chain = true)
 @ApiModel(description = "课程用户学习日志")
+@JsonInclude(NON_NULL)
 public class StudentStudyVO implements Serializable {
     private static final long serialVersionUID = 1L;
     @ApiModelProperty(value = "章节ID")
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/domain/vo/TrainRecordVO.java b/exam-system/src/main/java/com/gkhy/exam/system/domain/vo/TrainRecordVO.java
new file mode 100644
index 0000000..173b41f
--- /dev/null
+++ b/exam-system/src/main/java/com/gkhy/exam/system/domain/vo/TrainRecordVO.java
@@ -0,0 +1,32 @@
+package com.gkhy.exam.system.domain.vo;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+
+import java.time.LocalDateTime;
+
+import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL;
+
+@Setter
+@Getter
+@Accessors(chain = true)
+@ApiModel(description = "培训记录对象")
+@JsonInclude(NON_NULL)
+public class TrainRecordVO {
+    @ApiModelProperty(value = "学员id")
+    private Long studentId;
+    @ApiModelProperty(value = "培训类型(1批次学习 2考试)")
+    private Integer trainType;
+    @ApiModelProperty(value = "批次或者考试名称")
+    private String name;
+    @ApiModelProperty(value = "培训时间")
+    private LocalDateTime createTime;
+    @ApiModelProperty(value = "公司id")
+    private Long companyId;
+    @ApiModelProperty(value = "公司名称")
+    private String companyName;
+}
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/domain/vo/UploadObjectVO.java b/exam-system/src/main/java/com/gkhy/exam/system/domain/vo/UploadObjectVO.java
index d51d887..2fe6118 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/domain/vo/UploadObjectVO.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/domain/vo/UploadObjectVO.java
@@ -17,6 +17,10 @@
     @ApiModelProperty("文件保存相对路径")
     private String path;
 
+    @ApiModelProperty("文件访问链接")
+    private String  url;
+
+
     @ApiModelProperty("文件原始名称")
     private String originName;
 
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExCourseChapterPeriodMapper.java b/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExCourseChapterPeriodMapper.java
index 97c60be..05d89d2 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExCourseChapterPeriodMapper.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExCourseChapterPeriodMapper.java
@@ -47,4 +47,11 @@
      * @return
      */
     int deletePeriodByChapterId(Long chapterId);
+
+    /**
+     * 根据课程id获取课时数量
+     * @param courseId
+     * @return
+     */
+    int selectCountByCourseId(Long courseId);
 }
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExCourseMapper.java b/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExCourseMapper.java
index acc9555..0bf562d 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExCourseMapper.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExCourseMapper.java
@@ -3,6 +3,7 @@
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.gkhy.exam.system.domain.ExCourse;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
 
 import java.util.List;
 
@@ -36,7 +37,7 @@
      * @param name
      * @return
      */
-    ExCourse checkNameUnique(String name);
+    ExCourse checkNameUnique(@Param("name") String name, @Param("companyId") Long companyId);
 
     /**
      * 根据id删除
@@ -52,6 +53,13 @@
      */
     int selectCourseState(Long courseId);
 
+    /**
+     * 根据课程id查询课程绑定数量
+     * @param categoryId
+     * @return
+     */
+    int selectCountByCategoryId(Long categoryId);
+
 
 
 
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExExamPaperMapper.java b/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExExamPaperMapper.java
index 7ac72ff..2fe9458 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExExamPaperMapper.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExExamPaperMapper.java
@@ -51,6 +51,6 @@
      * @param name
      * @return
      */
-    ExExamPaper checkNameUnique(String name);
+    ExExamPaper checkNameUnique(@Param("name") String name,@Param("companyId") Long companyId);
 
 }
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExPaperQuestionMapper.java b/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExPaperQuestionMapper.java
index 77745ef..8840f25 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExPaperQuestionMapper.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExPaperQuestionMapper.java
@@ -3,6 +3,7 @@
 import com.gkhy.exam.system.domain.ExPaperQuestion;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
 
 import java.util.List;
 
@@ -31,7 +32,7 @@
     /**
      * 删除考卷下试题
      * @param paperId
-     * @param code
+     * @param questionType
      */
-    void deletePaperQuestion(Long paperId, Integer code);
+    void deletePaperQuestion(@Param("paperId") Long paperId, @Param("questionType") Integer questionType);
 }
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExPaperStudentMapper.java b/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExPaperStudentMapper.java
index 0bf8f53..cd0e45e 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExPaperStudentMapper.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExPaperStudentMapper.java
@@ -66,4 +66,29 @@
      * @return
      */
     ExPaperStudent selectByPaperStudentId(ExPaperStudent paperStudent);
+
+    /**
+     * 根据学员id获取学员分配的考试列表
+     * @param studentId
+     * @return
+     */
+    List<ExPaperStudent> selectByStudentId(Long studentId);
+
+    /**
+     * 分页获取未完成考试学生列表
+     * @param startIndex
+     * @param pageSize
+     * @return
+     */
+    List<ExPaperStudent> selectNoCompleteStudent(int startIndex,int pageSize);
+
+    /**
+     * 批量更新完成状态
+     * @param paperStudentIds
+     * @param completed
+     */
+    void batchUpdateComplete(@Param("paperStudentIds") List<Long> paperStudentIds,@Param("completed") Integer completed);
+
+
+
 }
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExPhaseStudentMapper.java b/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExPhaseStudentMapper.java
index 9412674..36a29cb 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExPhaseStudentMapper.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExPhaseStudentMapper.java
@@ -52,4 +52,11 @@
      * @return
      */
     Integer selectCountByPhaseStudentId(@Param("phaseId") Long phaseId, @Param("studentId")Long studentId);
+
+    /**
+     * 根据学员id获取学员批次分配列表
+     * @param studentId
+     * @return
+     */
+    public List<ExPhaseStudent> selectPhaseStudentByStudentId(Long studentId);
 }
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExQuestionBankMapper.java b/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExQuestionBankMapper.java
index e68b0de..325098f 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExQuestionBankMapper.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExQuestionBankMapper.java
@@ -60,4 +60,26 @@
      * @return
      */
     ExQuestionBank selectQuestionBankByIdForStudent(@Param("bankId") Long bankId,@Param("studentId") Long studentId);
+
+    /**
+     * 查询题库题目数量
+     * @param bankId
+     * @return
+     */
+    int selectCountByBankId(Long bankId);
+
+
+    /**
+     * 根据课程id查询题库绑定数量
+     * @param categoryId
+     * @return
+     */
+    int selectCountByCategoryId(Long categoryId);
+
+    /**
+     * 根据id列表查询题库
+     * @param bankIds
+     * @return
+     */
+    List<ExQuestionBank> selectQuestionBankByIds(List<Long> bankIds);
 }
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExQuestionMapper.java b/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExQuestionMapper.java
index 499a7b1..ec5d335 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExQuestionMapper.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExQuestionMapper.java
@@ -27,6 +27,13 @@
     Integer selectCountByBankId(@Param("companyId") Long companyId,@Param("bankId") Long bankId, @Param("questionType") Integer questionType);
 
     /**
+     * 根据id获取题目信息
+     * @param questionId
+     * @return
+     */
+    ExQuestion selectByQuestionId(Long questionId);
+
+    /**
      * 顺序获取指定数量的考题
      * @param bankId
      * @param questionType
@@ -53,10 +60,9 @@
     /**
      * 获取题库下面所有题目id列表
      * @param bankId
-     * @param exerciseType
      * @return
      */
-    List<Map> getExerciseQuestionList(@Param("bankId") Long bankId, @Param("exerciseType") Integer exerciseType,@Param("studentId") Long StundentId);
+    List<Map> getExerciseQuestionList(@Param("bankId") Long bankId,@Param("studentId") Long StundentId);
 
     /**
      * 刷题模式下获取题目
@@ -76,36 +82,43 @@
     /**
      * 获取考卷下面所有题目id列表
      * @param paperId
-     * @param completed
-     * @param userId
+     * @param state
+     * @param studentId
      * @return
      */
-    List<Map> getPaperQuestionList(@Param("paperId") Long paperId, @Param("completed") Integer completed, @Param("userId")Long userId);
+    List<Map> getPaperQuestionList(@Param("paperId") Long paperId, @Param("state") Integer state, @Param("studentId")Long studentId, @Param("viewType")Integer viewType);
 
     /**
      * 根据id获取考卷下题目详情
      * @param questionId
-     * @param completed
-     * @param userId
+     * @param state
+     * @param studentId
      * @return
      */
-    ExQuestion getPaperQuestionById(@Param("paperId")Long paperId,@Param("questionId")Long questionId, @Param("completed")Integer completed, @Param("userId")Long userId);
+    ExQuestion getPaperQuestionById(@Param("paperId")Long paperId,@Param("questionId")Long questionId, @Param("state")Integer state, @Param("studentId")Long studentId);
 
     /**
      * 根据id列表批量获取考卷下题目详情
      * @param paperId
      * @param questionIds
-     * @param completed
-     * @param userId
+     * @param state
+     * @param studentId
      * @return
      */
-    List<ExQuestion> getPaperQuestionByIds(@Param("paperId") Long paperId, @Param("questionIds")List<Long> questionIds, @Param("completed")Integer completed, @Param("userId")Long userId);
+    List<ExQuestion> getPaperQuestionByIds(@Param("paperId") Long paperId, @Param("questionIds")List<Long> questionIds, @Param("state")Integer state, @Param("studentId")Long studentId);
 
     /**
      * 获取错题题目id
      * @param bankId
-     * @param userId
+     * @param studentId
      * @return
      */
-    List<Long> getExerciseErrorQuestionList(@Param("bankId") Long bankId, @Param("userId") Long userId);
+    List<Long> getExerciseErrorQuestionList(@Param("bankId") Long bankId, @Param("studentId") Long studentId);
+
+    /**
+     * 根据试卷id查询题目列表
+     * @param paperId
+     * @return
+     */
+    List<ExQuestion> selectQuestionByPaperId(Long paperId);
 }
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExResourceMapper.java b/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExResourceMapper.java
index 14389d7..b75697e 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExResourceMapper.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExResourceMapper.java
@@ -45,4 +45,11 @@
      * @return
      */
     ExResource selectResourceByPeriodId(Long periodId);
+
+    /**
+     * 查看资源是否被分配
+     * @param resourceId
+     * @return
+     */
+    int checkResourceAssign(Long resourceId);
 }
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExStudentMapper.java b/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExStudentMapper.java
index 7cb22b9..3878843 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExStudentMapper.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/mapper/ExStudentMapper.java
@@ -57,4 +57,7 @@
      * @return
      */
     int deleteByStudentId(Long studentId);
+
+
+
 }
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/mapper/SysCategoryMapper.java b/exam-system/src/main/java/com/gkhy/exam/system/mapper/SysCategoryMapper.java
index 39c660c..0c0421f 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/mapper/SysCategoryMapper.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/mapper/SysCategoryMapper.java
@@ -34,17 +34,9 @@
     SysCategory checkNameUnique(@Param("name") String name, @Param("parentId")Long parentId);
 
     /**
-     * 根据课程id查询课程绑定数量
+     * 根据id删除分类
      * @param categoryId
      * @return
      */
-    int selectCountOfCoure(Long categoryId);
-
-
-    /**
-     * 根据课程id查询题库绑定数量
-     * @param categoryId
-     * @return
-     */
-    int selectCountOfBank(Long categoryId);
+    int deleteByCategoryId(Long categoryId);
 }
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/mapper/SysUserMapper.java b/exam-system/src/main/java/com/gkhy/exam/system/mapper/SysUserMapper.java
index 6dd2996..6999462 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/mapper/SysUserMapper.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/mapper/SysUserMapper.java
@@ -66,4 +66,11 @@
      * @return
      */
     SysUser checkPhoneUnique(String phone);
+
+    /**
+     * 根据部门账号id获取车间级账号id列表
+     * @param departUserId
+     * @return
+     */
+    List<Long> selectWorkshopUserIds(Long departUserId);
 }
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 b76d2b7..92e0033 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
@@ -3,9 +3,10 @@
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.gkhy.exam.common.api.CommonPage;
 import com.gkhy.exam.system.domain.ExPaperStudent;
+import com.gkhy.exam.system.domain.vo.BatchPaperStudentVO;
+import com.gkhy.exam.system.domain.vo.ExPaperStudentVO;
 
 import java.util.List;
-import java.util.Map;
 
 /**
  * <p>
@@ -26,10 +27,10 @@
 
     /**
      * 批量新增考卷与学员关系
-     * @param paperStudentMap
+     * @param batchPaperStudentVO
      * @return
      */
-    public int batchAddPaperStudent(Map<String,Object> paperStudentMap);
+    public int batchAddPaperStudent(BatchPaperStudentVO batchPaperStudentVO);
 
     /**
      * 分页获取学员的试卷列表
@@ -89,4 +90,16 @@
      */
     public void checkStudentUnique(List<ExPaperStudent> paperStudents);
 
+    /**
+     * 批改试卷
+     * @param paperStudentVO
+     */
+    public void doReview(ExPaperStudentVO paperStudentVO);
+
+    /**
+     * 计算试卷分数
+     * @param paperStudent
+     */
+    public void handlePaperData(ExPaperStudent paperStudent);
+
 }
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/service/ExQuestionService.java b/exam-system/src/main/java/com/gkhy/exam/system/service/ExQuestionService.java
index ef36566..d4105f9 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/service/ExQuestionService.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/service/ExQuestionService.java
@@ -60,10 +60,9 @@
     /**
      * 获取题目ID列表
      * @param bankId
-     * @param exerciseType
      * @return
      */
-    List<Map> getExerciseQuestionList(Long bankId, Integer exerciseType);
+    List<Map> getExerciseQuestionList(Long bankId);
 
     /**
      * 刷题模式下根据id获取题目
@@ -108,4 +107,11 @@
      * @return
      */
     List<Long> getExerciseErrorQuestionList(Long bankId);
+
+    /**
+     * 根据考卷获取题目列表
+     * @param paperId
+     * @return
+     */
+    List<ExQuestion> selectQuestionByPaperId(Long paperId);
 }
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/service/ExStudentService.java b/exam-system/src/main/java/com/gkhy/exam/system/service/ExStudentService.java
index 839372d..0ae0d21 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/service/ExStudentService.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/service/ExStudentService.java
@@ -3,6 +3,10 @@
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.gkhy.exam.common.api.CommonPage;
 import com.gkhy.exam.system.domain.ExStudent;
+import com.gkhy.exam.system.domain.vo.TrainRecordVO;
+
+import java.util.List;
+import java.util.Map;
 
 /**
  * <p>
@@ -80,15 +84,28 @@
     public boolean checkIdNoUnique(ExStudent student);
 
     /**
-     * 校验身份证号是否存在,存在则放回公司信息
+     * 校验身份证号是否存在,供前端校验使用
      * @param idNo
      * @return
      */
-    public ExStudent checkIdNoUnique(String idNo);
+    public Map checkIdNoUnique(String idNo);
 
     /**
      * 重置密码
      * @param student
      */
     boolean resetUserPwd(ExStudent student);
+
+    /**
+     * 变更学员所属公司
+     * @param bodyMap
+     */
+    void changeStudentCompany(Map<String, Long> bodyMap);
+
+    /**
+     * 获取学员培训记录
+     * @param studentId
+     * @return
+     */
+    List<TrainRecordVO> trainRecord(Long studentId);
 }
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 9641b9f..9181309 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
@@ -60,4 +60,7 @@
      * @param path
      */
     void removeMinioFile(Long resourceId,String path);
+
+
+    void importStudent();
 }
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/service/SysUserService.java b/exam-system/src/main/java/com/gkhy/exam/system/service/SysUserService.java
index 316330c..ae2c7f5 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/service/SysUserService.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/service/SysUserService.java
@@ -107,4 +107,5 @@
      */
     SysUser checkUserDataScope(Long userId);
 
+
 }
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExCourseChapterPeriodServiceImpl.java b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExCourseChapterPeriodServiceImpl.java
index 07bd4f0..b70b3fe 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExCourseChapterPeriodServiceImpl.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExCourseChapterPeriodServiceImpl.java
@@ -101,12 +101,15 @@
         if(currentUser.getUserType().equals(UserTypeEnum.STUDENT.getCode())){
             throw new ApiException("没有权限操作");
         }
-        if(!currentUser.getCompanyId().equals(courseChapterPeriod.getCompanyId())){
+        if(courseChapterPeriod.getCompanyId()!=null&&!currentUser.getCompanyId().equals(courseChapterPeriod.getCompanyId())){
             throw new ApiException("没有权限操作其他企业课程");
         }
         int state=courseMapper.selectCourseState(courseChapterPeriod.getCourseId());
         if(state== ApproveStatusEnum.APPROVED.getCode()){
-            throw new ApiException("已审批的课程不能再修改");
+            throw new ApiException("已审批的课程不能再操作");
+        }
+        if(state== ApproveStatusEnum.APPROVING.getCode()){
+            throw new ApiException("待审批的课程不能再操作");
         }
     }
 
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExCourseChapterServiceImpl.java b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExCourseChapterServiceImpl.java
index cccabeb..e74deb4 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExCourseChapterServiceImpl.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExCourseChapterServiceImpl.java
@@ -2,6 +2,7 @@
 
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.gkhy.exam.common.api.CommonPage;
+import com.gkhy.exam.common.config.MinioConfig;
 import com.gkhy.exam.common.constant.UserConstant;
 import com.gkhy.exam.common.domain.entity.SysUser;
 import com.gkhy.exam.common.enums.ApproveStatusEnum;
@@ -10,6 +11,8 @@
 import com.gkhy.exam.common.utils.PageUtils;
 import com.gkhy.exam.common.utils.SecurityUtils;
 import com.gkhy.exam.system.domain.ExCourseChapter;
+import com.gkhy.exam.system.domain.ExCourseChapterPeriod;
+import com.gkhy.exam.system.domain.ExResource;
 import com.gkhy.exam.system.mapper.ExCourseChapterMapper;
 import com.gkhy.exam.system.mapper.ExCourseChapterPeriodMapper;
 import com.gkhy.exam.system.mapper.ExCourseMapper;
@@ -34,6 +37,9 @@
     private ExCourseChapterPeriodMapper courseChapterPeriodMapper;
     @Autowired
     private ExCourseMapper courseMapper;
+
+    @Autowired
+    private MinioConfig minioConfig;
 
     @Override
     public CommonPage selectChapterList(ExCourseChapter chapter) {
@@ -116,7 +122,19 @@
 
     @Override
     public List<ExCourseChapter> selectChapterByCourseId(Long courseId,Integer status) {
-        return baseMapper.selectChapterByCourseId(courseId,null);
+        List<ExCourseChapter> courseChapterList= baseMapper.selectChapterByCourseId(courseId,null);
+        for(ExCourseChapter courseChapter:courseChapterList){
+            if(courseChapter.getChapterPeriods()!=null&& !courseChapter.getChapterPeriods().isEmpty()){
+                List<ExCourseChapterPeriod> courseChapterPeriodList=courseChapter.getChapterPeriods();
+                for(ExCourseChapterPeriod courseChapterPeriod:courseChapterPeriodList){
+                    if(courseChapterPeriod.getResource()!=null){
+                        ExResource resource=courseChapterPeriod.getResource();
+                        resource.setResourcePath(minioConfig.getEndpoint()+minioConfig.getBucketName()+"/"+resource.getResourcePath());
+                    }
+                }
+            }
+        }
+        return courseChapterList;
     }
 
 
@@ -128,12 +146,16 @@
         if(currentUser.getUserType().equals(UserTypeEnum.STUDENT.getCode())){
             throw new ApiException("没有权限操作");
         }
-        if(!currentUser.getCompanyId().equals(courseChapter.getCompanyId())){
+        if(courseChapter.getCompanyId()!=null&&!currentUser.getCompanyId().equals(courseChapter.getCompanyId())){
             throw new ApiException("没有权限操作其他企业课程");
         }
         int state=courseMapper.selectCourseState(courseChapter.getCourseId());
         if(state==ApproveStatusEnum.APPROVED.getCode()){
-            throw new ApiException("已审批的课程不能再修改");
+            throw new ApiException("已审批的课程不能再操作");
         }
+        if(state==ApproveStatusEnum.APPROVING.getCode()){
+            throw new ApiException("待审批的课程不能再操作");
+        }
+
     }
 }
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExCoursePhaseServiceImpl.java b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExCoursePhaseServiceImpl.java
index 82b319d..202ca2c 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExCoursePhaseServiceImpl.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExCoursePhaseServiceImpl.java
@@ -4,12 +4,15 @@
 import com.gkhy.exam.common.api.CommonPage;
 import com.gkhy.exam.common.constant.UserConstant;
 import com.gkhy.exam.common.domain.entity.SysUser;
+import com.gkhy.exam.common.enums.ApproveStatusEnum;
 import com.gkhy.exam.common.enums.CodeTypeEnum;
 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.ExCourse;
 import com.gkhy.exam.system.domain.ExCoursePhase;
+import com.gkhy.exam.system.mapper.ExCourseMapper;
 import com.gkhy.exam.system.mapper.ExCoursePhaseMapper;
 import com.gkhy.exam.system.mapper.ExPhaseStudentMapper;
 import com.gkhy.exam.system.service.ExCoursePhaseService;
@@ -31,6 +34,8 @@
 public class ExCoursePhaseServiceImpl extends ServiceImpl<ExCoursePhaseMapper, ExCoursePhase> implements ExCoursePhaseService {
     @Autowired
     private ExPhaseStudentMapper phaseStudentMapper;
+    @Autowired
+    private ExCourseMapper courseMapper;
 
 
 
@@ -64,6 +69,7 @@
     @Override
     public int insertCoursePhase(ExCoursePhase coursePhase) {
         checkUserAllowed(coursePhase);
+        checkCourseStatus(coursePhase);
         if(!checkNameUnique(coursePhase)){
             throw new ApiException("批次名称已存在");
         }
@@ -79,6 +85,7 @@
     @Override
     public int updateCoursePhase(ExCoursePhase coursePhase) {
         checkUserAllowed(coursePhase);
+        checkCourseStatus(coursePhase);
         if(!checkNameUnique(coursePhase)){
             throw new ApiException("批次名称已存在");
         }
@@ -98,7 +105,7 @@
         if(currentUser.getUserType().equals(UserTypeEnum.STUDENT.getCode())){
             throw new ApiException("没有权限操作");
         }
-        if(!currentUser.getCompanyId().equals(coursePhase.getCompanyId())){
+        if(coursePhase.getCompanyId()!=null&&!currentUser.getCompanyId().equals(coursePhase.getCompanyId())){
             throw new ApiException("没有权限操作其他企业批次");
         }
         int level=coursePhase.getLevel();
@@ -110,6 +117,18 @@
         }
     }
 
+
+    private void checkCourseStatus(ExCoursePhase coursePhase){
+        Long courseId=coursePhase.getCourseId();
+        ExCourse course= courseMapper.selectById(courseId);
+        if(course.getStatus().equals(UserConstant.DISENABLE)){
+            throw new ApiException("课程已禁用,不能分配");
+        }
+        if(!course.getState().equals(ApproveStatusEnum.APPROVED.getCode())){
+            throw new ApiException("课程审批未通过,不能分配");
+        }
+    }
+
     @Override
     public int deleteCoursePhaseById(Long phaseId) {
         checkUserAllowed(baseMapper.selectById(phaseId));
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 1fba51e..682e92b 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
@@ -10,6 +10,7 @@
 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.common.utils.StringUtils;
 import com.gkhy.exam.system.domain.ExCourse;
 import com.gkhy.exam.system.mapper.ExCourseChapterMapper;
 import com.gkhy.exam.system.mapper.ExCourseMapper;
@@ -78,7 +79,7 @@
             course.setState(ApproveStatusEnum.APPROVED.getCode());
             course.setPrivatize(PrivatizeEnum.PUBLIC.getCode());
         }else{
-            course.setState(ApproveStatusEnum.APPROVING.getCode());
+            course.setState(ApproveStatusEnum.TEMPORARY.getCode());
         }
         int row =baseMapper.insert(course);
         if(row<1){
@@ -112,8 +113,11 @@
             throw new ApiException("没有权限操作其他企业课程");
         }
         if(course.getId()!=null){
+            if(course.getState().equals(ApproveStatusEnum.APPROVING.getCode())){
+                throw new ApiException("课程待审批状态不能再操作");
+            }
             if(course.getState().equals(ApproveStatusEnum.APPROVED.getCode())){
-                throw new ApiException("已审批的课程不能再修改");
+                throw new ApiException("已审批的课程不能再操作");
             }
         }
     }
@@ -139,8 +143,9 @@
 
     @Override
     public boolean checkNameUnique(ExCourse course) {
+        SysUser user=SecurityUtils.getLoginUser().getUser();
         Long courseId=course.getId()==null?-1L:course.getId();
-        ExCourse cou= baseMapper.checkNameUnique(course.getName());
+        ExCourse cou= baseMapper.checkNameUnique(course.getName(),user.getCompanyId());
         if(cou!=null&&cou.getId().longValue()!=courseId.longValue()){
             return UserConstant.NOT_UNIQUE;
         }
@@ -149,8 +154,22 @@
 
     @Override
     public int doApprove(ExCourse course) {
-        ExCourse existCourse=baseMapper.selectById(course.getId());
-        checkUserAllowed(existCourse);
+        SysUser currentUser= SecurityUtils.getLoginUser().getUser();
+        ExCourse dbCourse=getById(course.getId());
+        if(!currentUser.getUserType().equals(UserTypeEnum.SYSTEM_USER.getCode())){
+            if(currentUser.getUserType().equals(UserTypeEnum.STUDENT.getCode())){
+                throw new ApiException("没有权限操作");
+            }
+            if(!currentUser.getCompanyId().equals(dbCourse.getCompanyId())){
+                throw new ApiException("没有权限操作其他企业课程");
+            }
+            if(dbCourse.getState().equals(ApproveStatusEnum.APPROVED.getCode())){
+                throw new ApiException("已审批的课程不能再操作");
+            }
+        }
+        if(StringUtils.isBlank(course.getMessage())){
+            course.setMessage("");
+        }
         int row=baseMapper.updateById(course);
         if(row<1){
             throw new ApiException("审批失败");
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 5bd7e0d..0b7b717 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
@@ -14,20 +14,15 @@
 import com.gkhy.exam.system.domain.ExExamPaper;
 import com.gkhy.exam.system.domain.ExPaperQuestion;
 import com.gkhy.exam.system.domain.ExQuestion;
-import com.gkhy.exam.system.mapper.ExExamPaperMapper;
-import com.gkhy.exam.system.mapper.ExPaperQuestionMapper;
-import com.gkhy.exam.system.mapper.ExPaperStudentMapper;
-import com.gkhy.exam.system.mapper.ExQuestionMapper;
+import com.gkhy.exam.system.domain.ExQuestionBank;
+import com.gkhy.exam.system.mapper.*;
 import com.gkhy.exam.system.service.ExExamPaperService;
 import com.gkhy.exam.system.utils.SequenceUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-import java.util.Random;
+import java.util.*;
 import java.util.stream.Collectors;
 
 /**
@@ -47,6 +42,8 @@
     private ExPaperQuestionMapper paperQuestionMapper;
     @Autowired
     private ExQuestionMapper questionMapper;
+    @Autowired
+    private ExQuestionBankMapper questionBankMapper;
 
     @Autowired
     private SequenceUtils sequenceUtils;
@@ -65,6 +62,27 @@
     @Override
     public ExExamPaper selectExamPaperById(Long paperId) {
         ExExamPaper examPaper= baseMapper.selectExamPaperById(paperId);
+        //获取题库名称
+        List<Long> bankIds=new ArrayList<>();
+        bankIds.add(examPaper.getSingleBankId());
+        bankIds.add(examPaper.getMultiBankId());
+        bankIds.add(examPaper.getJudgeBankId());
+        bankIds.add(examPaper.getEasyBankId());
+        List<ExQuestionBank> questionBanks=questionBankMapper.selectQuestionBankByIds(bankIds);
+        questionBanks.forEach(item -> {
+            if(Objects.equals(item.getId(), examPaper.getSingleBankId())){
+                examPaper.setSingleBankName(item.getName());
+            }
+            if(Objects.equals(item.getId(), examPaper.getMultiBankId())){
+                examPaper.setMultiBankName(item.getName());
+            }
+            if(Objects.equals(item.getId(), examPaper.getJudgeBankId())){
+                examPaper.setJudgeBankName(item.getName());
+            }
+            if(Objects.equals(item.getId(), examPaper.getEasyBankId())){
+                examPaper.setEasyBankName(item.getName());
+            }
+        });
         SysUser currentUser= SecurityUtils.getLoginUser().getUser();
         if(currentUser.getUserType().equals(UserTypeEnum.SYSTEM_USER.getCode())){
             return examPaper;
@@ -79,6 +97,7 @@
     @Override
     @Transactional(rollbackFor = RuntimeException.class)
     public int insertExamPaper(ExExamPaper examPaper) {
+        validatedData(examPaper);
         checkUserAllowed(examPaper);
         if(!checkNameUnique(examPaper)){
             throw new ApiException("试卷名称已存在");
@@ -87,18 +106,27 @@
         examPaper.setCode(sequenceUtils.getNextSequence(CodeTypeEnum.EXAM_PAPER.getCode()));
         examPaper.setCreateBy(SecurityUtils.getUsername());
         if(examPaper.getLimitTime()>0){
-            examPaper.setLimit(1);
+            examPaper.setLimited(1);
         }else{
-            examPaper.setLimit(0);
+            examPaper.setLimited(0);
         }
         int row=baseMapper.insert(examPaper);
         if(row<1){
             throw new ApiException("新增试卷失败");
         }
         //分配试题
-        assignSingleQuestion(examPaper);
-        assignMultiQuestion(examPaper);
-        assignJudgeQuestion(examPaper);
+        if(Optional.ofNullable(examPaper.getSingleNum()).orElse(0)>0) {
+            assignSingleQuestion(examPaper);
+        }
+        if(Optional.ofNullable(examPaper.getMultiNum()).orElse(0)>0) {
+            assignMultiQuestion(examPaper);
+        }
+        if(Optional.ofNullable(examPaper.getJudgeNum()).orElse(0)>0) {
+            assignJudgeQuestion(examPaper);
+        }
+        if(Optional.ofNullable(examPaper.getEasyNum()).orElse(0)>0) {
+            assignEasyQuestion(examPaper);
+        }
         return row;
     }
 
@@ -110,8 +138,37 @@
         if(currentUser.getUserType().equals(UserTypeEnum.STUDENT.getCode())){
             throw new ApiException("没有权限操作");
         }
-        if(!currentUser.getCompanyId().equals(examPaper.getCompanyId())){
+        if(examPaper.getCompanyId()!=null&&!currentUser.getCompanyId().equals(examPaper.getCompanyId())){
             throw new ApiException("没有权限操作其他企业试卷");
+        }
+    }
+
+    public void validatedData(ExExamPaper examPaper){
+        if(Optional.ofNullable(examPaper.getSingleNum()).orElse(0)<=0
+        &&Optional.ofNullable(examPaper.getMultiNum()).orElse(0)<=0
+        &&Optional.ofNullable(examPaper.getJudgeNum()).orElse(0)<=0
+        &&Optional.ofNullable(examPaper.getEasyNum()).orElse(0)<=0){
+            throw new ApiException("试卷题目数量不能为空");
+        }
+        if(Optional.ofNullable(examPaper.getSingleNum()).orElse(0)>0){
+            if(Optional.ofNullable(examPaper.getSingleScore()).orElse(0)<=0 || examPaper.getSingleMethod()==null||examPaper.getSingleBankId()==null){
+                throw new ApiException("单选题参数错误");
+            }
+        }
+        if(Optional.ofNullable(examPaper.getMultiNum()).orElse(0)>0){
+            if(Optional.ofNullable(examPaper.getMultiScore()).orElse(0)<=0 || examPaper.getMultiMethod()==null||examPaper.getMultiBankId()==null){
+                throw new ApiException("多选题参数错误");
+            }
+        }
+        if(Optional.ofNullable(examPaper.getJudgeNum()).orElse(0)>0){
+            if(Optional.ofNullable(examPaper.getJudgeScore()).orElse(0)<=0 || examPaper.getJudgeMethod()==null||examPaper.getJudgeBankId()==null){
+                throw new ApiException("判断题参数错误");
+            }
+        }
+        if(Optional.ofNullable(examPaper.getEasyNum()).orElse(0)>0){
+            if(Optional.ofNullable(examPaper.getEasyScore()).orElse(0)<=0 || examPaper.getEasyMethod()==null||examPaper.getEasyBankId()==null){
+                throw new ApiException("简答题参数错误");
+            }
         }
     }
 
@@ -136,6 +193,13 @@
         paperQuestionMapper.batchInsert(paperQuestionList);
     }
 
+    //分配简答题
+    public void assignEasyQuestion(ExExamPaper examPaper){
+        List<ExPaperQuestion> paperQuestionList = getPaperQuestions(examPaper.getId(), examPaper.getEasyBankId(),
+                examPaper.getEasyMethod(),examPaper.getEasyNum(), examPaper.getEasyScore(),QuestionTypeEnum.EASY);
+        paperQuestionMapper.batchInsert(paperQuestionList);
+    }
+
     private List<ExPaperQuestion> getPaperQuestions(Long paperId,Long bankId,Integer questionMethod,Integer questionCount,Integer questionScore, QuestionTypeEnum questionTypeEnum) {
         SysUser currentUser=SecurityUtils.getLoginUser().getUser();
         Integer totalQuestionCount=questionMapper.selectCountByBankId(currentUser.getCompanyId(), bankId, questionTypeEnum.getCode());
@@ -146,7 +210,7 @@
         if(Objects.equals(questionMethod, QuestionAssignEnum.RANDOM.getCode())){//随机分配
             questions=questionMapper.selectRandomQuestion(currentUser.getCompanyId(), bankId,questionTypeEnum.getCode(), questionCount);
         }else{//顺序分配
-            int totalPage=questionCount/questionMethod;//不能整除,忽略最后一页
+            int totalPage=totalQuestionCount/questionCount;//不能整除,忽略最后一页
             Random random=new Random();
             int startIndex=random.nextInt(totalPage)+1;
             questions=questionMapper.selectQuestionWithLimit(currentUser.getCompanyId(), bankId,questionTypeEnum.getCode(),startIndex, questionCount);
@@ -164,6 +228,7 @@
 
     @Override
     public int updateExamPaper(ExExamPaper examPaper) {
+        validatedData(examPaper);
         checkUserAllowed(examPaper);
         if(!checkNameUnique(examPaper)){
             throw new ApiException("试卷名称已存在");
@@ -174,9 +239,10 @@
         }
         examPaper.setCode(null);//编号不能修改
         if(examPaper.getLimitTime()>0){
-            examPaper.setLimit(1);
+            examPaper.setLimited(1);
         }else{
-            examPaper.setLimit(0);
+            examPaper.setLimited(0);
+            examPaper.setLimitTime(0);
         }
         int row=baseMapper.updateById(examPaper);
         if(row<1){
@@ -194,6 +260,10 @@
         if(examPaper.getJudgeRebuild()==1) {
            deletePaperQuestion(examPaper.getId(),QuestionTypeEnum.JUDGE);
            assignJudgeQuestion(examPaper);
+        }
+        if(examPaper.getEasyRebuild()==1) {
+            deletePaperQuestion(examPaper.getId(),QuestionTypeEnum.EASY);
+            assignEasyQuestion(examPaper);
         }
         return row;
     }
@@ -229,8 +299,9 @@
 
     @Override
     public boolean checkNameUnique(ExExamPaper examPaper) {
+        SysUser currentUser=SecurityUtils.getLoginUser().getUser();
         Long paperId=examPaper.getId()==null?-1L:examPaper.getId();
-        ExExamPaper paper= baseMapper.checkNameUnique(examPaper.getName());
+        ExExamPaper paper= baseMapper.checkNameUnique(examPaper.getName(),currentUser.getCompanyId());
         if(paper!=null&&paper.getId().longValue()!=paperId.longValue()){
             return UserConstant.NOT_UNIQUE;
         }
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
index a0479b9..814f370 100644
--- 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
@@ -46,6 +46,8 @@
     @Override
     public int insertExamRecord(ExExamRecord examRecord) {
         checkUserAllowed(examRecord);
+        examRecord.setCompanyId(SecurityUtils.getLoginUser().getUser().getCompanyId());
+        examRecord.setCreateBy(SecurityUtils.getUsername());
         int row=baseMapper.insert(examRecord);
         if(row<1){
             throw new ApiException("新增登记记录失败");
@@ -56,6 +58,7 @@
     @Override
     public int updateExamRecord(ExExamRecord examRecord) {
         checkUserAllowed(examRecord);
+        examRecord.setUpdateBy(SecurityUtils.getUsername());
         int row=baseMapper.updateById(examRecord);
         if(row<1){
             throw new ApiException("更新登记记录失败");
@@ -72,12 +75,12 @@
     public void checkUserAllowed(ExExamRecord examRecord) {
         SysUser currentUser= SecurityUtils.getLoginUser().getUser();
         if(currentUser.getUserType().equals(UserTypeEnum.SYSTEM_USER.getCode())){
-            return;
+            throw new ApiException("管理员没有权限操作");
         }
         if(currentUser.getUserType().equals(UserTypeEnum.STUDENT.getCode())){
             throw new ApiException("没有权限操作");
         }
-        if(!currentUser.getCompanyId().equals(examRecord.getCompanyId())){
+        if(examRecord.getCompanyId()!=null&&!currentUser.getCompanyId().equals(examRecord.getCompanyId())){
             throw new ApiException("没有权限操作其他企业登记记录");
         }
     }
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExExerciseAnswerServiceImpl.java b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExExerciseAnswerServiceImpl.java
index 93c062a..03032d7 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExExerciseAnswerServiceImpl.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExExerciseAnswerServiceImpl.java
@@ -1,7 +1,9 @@
 package com.gkhy.exam.system.service.impl;
 
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.gkhy.exam.common.enums.StudentAnswerPassEnum;
 import com.gkhy.exam.common.exception.ApiException;
+import com.gkhy.exam.common.utils.SecurityUtils;
 import com.gkhy.exam.system.domain.ExExerciseAnswer;
 import com.gkhy.exam.system.domain.ExQuestion;
 import com.gkhy.exam.system.domain.ExStudentAnswer;
@@ -27,11 +29,12 @@
     @Override
     public ExExerciseAnswer addExerciseAnswer(ExExerciseAnswer exerciseAnswer) {
         int row=0;
+        exerciseAnswer.setStudentId(SecurityUtils.getUserId());
         ExQuestion question=questionMapper.selectById(exerciseAnswer.getQuestionId());
         if(exerciseAnswer.getAnswer().equals(question.getAnswer())){
-            exerciseAnswer.setPassed(1);
+            exerciseAnswer.setPassed(StudentAnswerPassEnum.CORRECT.getCode());
         }else{
-            exerciseAnswer.setPassed(0);
+            exerciseAnswer.setPassed(StudentAnswerPassEnum.ERROR.getCode());
         }
         ExExerciseAnswer existAnswer= baseMapper.getExerciseAnswer(exerciseAnswer);
         if(existAnswer!=null){
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 cd57bf4..63de6e3 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
@@ -4,18 +4,22 @@
 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.constant.Constant;
 import com.gkhy.exam.common.domain.entity.SysUser;
+import com.gkhy.exam.common.enums.PaperStudentStateEnum;
 import com.gkhy.exam.common.enums.QuestionTypeEnum;
+import com.gkhy.exam.common.enums.StudentAnswerPassEnum;
 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.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.common.utils.StringUtils;
+import com.gkhy.exam.system.domain.*;
+import com.gkhy.exam.system.domain.vo.BatchPaperStudentVO;
+import com.gkhy.exam.system.domain.vo.ExPaperStudentVO;
 import com.gkhy.exam.system.mapper.*;
 import com.gkhy.exam.system.service.ExPaperStudentService;
+import com.gkhy.exam.system.service.ExStudentAnswerService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -36,11 +40,15 @@
     @Autowired
     private ExExamPaperMapper examPaperMapper;
     @Autowired
+    private ExStudentAnswerService studentAnswerService;
+    @Autowired
     private ExStudentAnswerMapper studentAnswerMapper;
     @Autowired
     private ExStudentMapper studentMapper;
     @Autowired
     private ExPhaseStudentMapper phaseStudentMapper;
+    @Autowired
+    private ExQuestionMapper questionMapper;
 
 
     @Override
@@ -78,26 +86,38 @@
     }
 
     @Override
-    public int batchAddPaperStudent(Map<String,Object> paperStudentMap) {
-        List<Long> phaseIds= (List<Long>) paperStudentMap.get("phaseIds");
-        List<Long> studentIds= (List<Long>) paperStudentMap.get("studentIds");
+    public int batchAddPaperStudent(BatchPaperStudentVO batchPaperStudentVO) {
+        List<Long> phaseIds= batchPaperStudentVO.getPhaseIds();
+        List<Long> studentIds= batchPaperStudentVO.getStudentIds();
+        Long paperId=batchPaperStudentVO.getPaperId();
         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不能为空");
-        }
+        List<Long> allStudentIds=new ArrayList<>();
         //按批次绑定用户
-        if(phaseIds.size()>0){
+        if(phaseIds!=null&&!phaseIds.isEmpty()){
             List<ExPhaseStudent> phaseStudentList=phaseStudentMapper.selectList( Wrappers.<ExPhaseStudent>lambdaQuery()
                     .in(ExPhaseStudent::getPhaseId, phaseIds));
-            studentIds=phaseStudentList.stream().map(item -> item.getStudentId()).distinct().collect(Collectors.toList());
+            allStudentIds=phaseStudentList.stream().map(item -> item.getStudentId()).distinct().collect(Collectors.toList());
         }
-        List<ExPaperStudent> paperStudents=studentIds.stream().map(item -> {
-            return new ExPaperStudent().setPaperId(paperId).setStudentId(item);
+        if(studentIds!=null&&!studentIds.isEmpty()){
+            allStudentIds.addAll(studentIds);
+        }
+        List<ExPaperStudent> paperStudentList=baseMapper.selectList( Wrappers.<ExPaperStudent>lambdaQuery()
+                .eq(true,ExPaperStudent::getPaperId, paperId)
+                .in(true,ExPaperStudent::getStudentId,allStudentIds));
+        if(paperStudentList.size()>0) {
+            List<Long> existStudentIds = paperStudentList.stream().map(item -> item.getStudentId()).distinct().collect(Collectors.toList());
+            allStudentIds.removeAll(existStudentIds);
+        }
+        if(allStudentIds.isEmpty()){
+            throw new ApiException("未匹配到学员");
+        }
+        allStudentIds= allStudentIds.stream().distinct().collect(Collectors.toList());
+        List<ExPaperStudent> paperStudents=allStudentIds.stream().map(item -> {
+            return new ExPaperStudent().setPaperId(paperId).setStudentId(item).setCreateId(SecurityUtils.getUserId());
         }).collect(Collectors.toList());
-        checkStudentUnique(paperStudents);
+      //  checkStudentUnique(paperStudents);
         int row=baseMapper.batchInsert(paperStudents);
         if(row<1){
             throw new ApiException("批量分配学员失败");
@@ -115,6 +135,57 @@
             }
         }
     }
+
+    @Override
+    @Transactional(rollbackFor = RuntimeException.class)
+    public void doReview(ExPaperStudentVO paperStudentVO) {
+        checkUserAllowed(new ExPaperStudent().setPaperId(paperStudentVO.getPaperId()));
+        ExPaperStudent paperStudent=baseMapper.selectById(paperStudentVO.getId());
+        ExExamPaper examPaper=examPaperMapper.selectById(paperStudent.getPaperId());
+        if(paperStudent.getState().equals(PaperStudentStateEnum.WAIT_EXAM.getCode())){
+            throw new ApiException("待考试状态的试卷不能批改!");
+        }
+        List<ExStudentAnswer> studentAnswerList=studentAnswerMapper.selectList(Wrappers.<ExStudentAnswer>lambdaQuery()
+                .eq(true,ExStudentAnswer::getStudentId,paperStudent.getStudentId())
+                .eq(true,ExStudentAnswer::getPaperId,paperStudent.getPaperId()));
+        Map<Long, ExStudentAnswer> collectMap = studentAnswerList.stream().collect(Collectors.toMap(ExStudentAnswer::getQuestionId, k -> k));
+        List<ExPaperStudentVO.QuestionVO> questionVOList=paperStudentVO.getQuestions();
+        List<ExStudentAnswer> updateStudentAnswerList=new ArrayList<>();
+        for (ExPaperStudentVO.QuestionVO questionVO:questionVOList){
+            ExStudentAnswer sa=collectMap.get(questionVO.getQuestionId());
+            if(sa!=null){
+                int score=questionVO.getScore();
+                sa.setScore(score);
+                if(score>examPaper.getEasyScore()){
+                    throw new ApiException("得分不能超过题目的最高分!");
+                }else if(score==examPaper.getEasyScore()){
+                    sa.setPassed(StudentAnswerPassEnum.CORRECT.getCode());
+                }else{
+                    sa.setPassed(StudentAnswerPassEnum.ERROR.getCode());
+                }
+                updateStudentAnswerList.add(sa);
+            }
+        }
+        int totalScore=0;
+        for(ExStudentAnswer studentAnswer:studentAnswerList){
+            if(studentAnswer.getScore()!=null) {
+                totalScore = totalScore + studentAnswer.getScore();
+            }
+        }
+        paperStudent.setState(PaperStudentStateEnum.DONE_REVIEW.getCode());
+        paperStudent.setScore(totalScore);
+        if(totalScore<examPaper.getPassScore()){
+            paperStudent.setPassed(Constant.EXAM_UNPASS);
+        }else{
+            paperStudent.setPassed(Constant.EXAM_PASS);
+        }
+        paperStudent.setUpdateBy(SecurityUtils.getUsername());
+        baseMapper.updateById(paperStudent);
+        if(!updateStudentAnswerList.isEmpty()){
+            studentAnswerService.updateBatchById(updateStudentAnswerList);
+        }
+    }
+
 
     @Override
     public CommonPage selectPaperStudentList(ExPaperStudent paperStudent) {
@@ -166,32 +237,96 @@
     }
 
     @Override
-    public void endExam(ExPaperStudent paperStudent) {
+    public void endExam(ExPaperStudent pStudent) {
+        if(pStudent.getId()==null){
+            throw new ApiException("学员与试卷关系id不能为空");
+        }
+        ExPaperStudent existPs=baseMapper.selectById(pStudent.getId());
+        if(existPs==null){
+            throw new ApiException("学员与试卷关系不存在");
+        }
         Long endTime=System.currentTimeMillis();
-        //异步计算
+        existPs.setEndTime(endTime);
+        handlePaperData(existPs);
+
+    }
+
+    @Override
+    @Transactional(rollbackFor = RuntimeException.class)
+    public void handlePaperData(ExPaperStudent paperStudent){
         //计算考试成绩
         ExExamPaper paper=examPaperMapper.selectById(paperStudent.getPaperId());
-        int singleCount=studentAnswerMapper.selectPassCount(paperStudent.getPaperId(),paperStudent.getStudentId(), QuestionTypeEnum.SINGLE.getCode());
-        int multiCount=studentAnswerMapper.selectPassCount(paperStudent.getPaperId(),paperStudent.getStudentId(), QuestionTypeEnum.MULTI.getCode());
-        int judgeCount=studentAnswerMapper.selectPassCount(paperStudent.getPaperId(),paperStudent.getStudentId(), QuestionTypeEnum.JUDGE.getCode());
-        int score=singleCount*paper.getSingleScore()+multiCount*paper.getMultiScore()+judgeCount*paper.getJudgeScore();
-        ExPaperStudent exPaperStudent = new ExPaperStudent()
-                .setPaperId(paperStudent.getPaperId())
-                .setStudentId(paperStudent.getStudentId())
-                .setCompleted(1)
-                .setEndTime(endTime)
-                .setScore(score);
-        if(score>=paper.getPassScore()){
-            exPaperStudent.setPassed(1);
-        }else{
-            exPaperStudent.setPassed(0);
+        paperStudent.setState(PaperStudentStateEnum.WAIT_REVIEW.getCode());
+        List<ExStudentAnswer> studentAnswerList=studentAnswerMapper.selectList(Wrappers.<ExStudentAnswer>lambdaQuery()
+                .eq(true,ExStudentAnswer::getStudentId,paperStudent.getStudentId())
+                .eq(true,ExStudentAnswer::getPaperId,paperStudent.getPaperId()));
+        List<ExQuestion> questionList=questionMapper.selectQuestionByPaperId(paperStudent.getPaperId());
+        Map<Long, ExStudentAnswer> collectMap = studentAnswerList.stream().collect(Collectors.toMap(ExStudentAnswer::getQuestionId, k -> k));
+        List<ExStudentAnswer> updateStudentAnswers=new ArrayList<>();
+        int totalScore=0;
+        boolean easyViewFlag=false;
+        for(ExQuestion question:questionList){
+            ExStudentAnswer sa=collectMap.get(question.getId());
+            if(sa!=null){
+                if(question.getQuestionType().equals(QuestionTypeEnum.EASY.getCode())) {
+                    if(StringUtils.isBlank(sa.getAnswer())){
+                        sa.setPassed(StudentAnswerPassEnum.ERROR.getCode());
+                        sa.setScore(0);
+                    }else{
+                        sa.setPassed(StudentAnswerPassEnum.WAIT_REVIEW.getCode());
+                        easyViewFlag=true;
+                    }
+                }else{
+                    if (sa.getAnswer().equals(question.getAnswer())) {
+                        sa.setPassed(StudentAnswerPassEnum.CORRECT.getCode());
+                        sa.setScore(getScore(paper, question.getQuestionType()));
+                        totalScore = totalScore + sa.getScore();
+                    }else {
+                        sa.setPassed(StudentAnswerPassEnum.ERROR.getCode());
+                        sa.setScore(0);
+                    }
+                }
+            }else{
+                sa=new ExStudentAnswer();
+                sa.setPassed(StudentAnswerPassEnum.ERROR.getCode());
+                sa.setScore(0);
+                sa.setStudentId(paperStudent.getStudentId());
+                sa.setPaperId(paperStudent.getPaperId());
+                sa.setQuestionId(question.getId());
+            }
+            updateStudentAnswers.add(sa);
         }
-        int row=baseMapper.updateById(exPaperStudent);
+
+        studentAnswerService.saveOrUpdateBatch(updateStudentAnswers);
+        paperStudent.setScore(totalScore);
+        if(!easyViewFlag){
+            //没有简答题,直接批改试卷
+            paperStudent.setState(PaperStudentStateEnum.DONE_REVIEW.getCode());
+            if(paper.getPassScore()>totalScore){
+                paperStudent.setPassed(Constant.EXAM_UNPASS);
+            }else{
+                paperStudent.setPassed(Constant.EXAM_PASS);
+            }
+        }
+        int row=baseMapper.updateById(paperStudent);
         if(row<1){
             throw new ApiException("提交考试失败");
         }
     }
 
+    private Integer getScore(ExExamPaper examPaper,Integer questionType){
+        if(questionType.equals(QuestionTypeEnum.SINGLE.getCode())){
+            return examPaper.getSingleScore();
+        }else if(questionType.equals(QuestionTypeEnum.MULTI.getCode())){
+            return examPaper.getMultiScore();
+        }else if(questionType.equals(QuestionTypeEnum.JUDGE.getCode())){
+            return examPaper.getJudgeScore();
+        }else if(questionType.equals(QuestionTypeEnum.EASY.getCode())){
+            return examPaper.getEasyScore();
+        }
+        return 0;
+    }
+
 
 
 }
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExPhaseStudentServiceImpl.java b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExPhaseStudentServiceImpl.java
index 1bc23d0..57b17ec 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExPhaseStudentServiceImpl.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExPhaseStudentServiceImpl.java
@@ -11,10 +11,7 @@
 import com.gkhy.exam.common.utils.SecurityUtils;
 import com.gkhy.exam.system.domain.*;
 import com.gkhy.exam.system.domain.vo.StudentStudyVO;
-import com.gkhy.exam.system.mapper.ExCoursePhaseMapper;
-import com.gkhy.exam.system.mapper.ExPhaseStudentMapper;
-import com.gkhy.exam.system.mapper.ExStudentMapper;
-import com.gkhy.exam.system.mapper.ExStudentStudyMapper;
+import com.gkhy.exam.system.mapper.*;
 import com.gkhy.exam.system.service.ExCompanyPeriodService;
 import com.gkhy.exam.system.service.ExPhaseStudentService;
 import com.gkhy.exam.system.service.ExStudentStudyService;
@@ -23,6 +20,7 @@
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.math.BigDecimal;
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
@@ -50,6 +48,8 @@
     private SysCompanyService companyService;
     @Autowired
     private ExCompanyPeriodService companyPeriodService;
+    @Autowired
+    private ExCourseChapterPeriodMapper courseChapterPeriodMapper;
 
 
     @Override
@@ -72,6 +72,9 @@
     @Override
     @Transactional(rollbackFor = RuntimeException.class)
     public int batchAddPhaseStudent(List<ExPhaseStudent> phaseStudents) {
+        if(phaseStudents==null|| phaseStudents.isEmpty()){
+            throw new ApiException("学员数据不能为空");
+        }
         checkUserAllowed(phaseStudents.get(0));
         checkStudentUnique(phaseStudents);
         for(ExPhaseStudent phaseStudent:phaseStudents){
@@ -96,7 +99,7 @@
             throw new ApiException("没有权限操作");
         }
         ExCoursePhase coursePhase=coursePhaseMapper.selectById(phaseStudent.getPhaseId());
-        if(!currentUser.getCompanyId().equals(coursePhase.getCompanyId())){
+        if(!coursePhase.getCompanyId().equals(currentUser.getCompanyId())){
             throw new ApiException("没有权限操作其他企业批次");
         }
 
@@ -110,6 +113,17 @@
         }
         PageUtils.startPage();
         List<ExPhaseStudent> phaseStudentList=baseMapper.selectPhaseStudentList(phaseStudent);
+        if(phaseStudentList.size()>0) {
+            //获取课程所有课时数量
+            int count = courseChapterPeriodMapper.selectCountByCourseId(phaseStudentList.get(0).getCourse().getId());
+            if(count>0) {
+                for (ExPhaseStudent ps : phaseStudentList) {
+                    if (ps.getTotalProgress() != null) {
+                        ps.setTotalProgress(ps.getTotalProgress().divide(BigDecimal.valueOf(count), BigDecimal.ROUND_UP));
+                    }
+                }
+            }
+        }
         return CommonPage.restPage(phaseStudentList);
     }
 
@@ -129,7 +143,7 @@
     public int deletePhaseStudent(Long phaseStudentId) {
         ExPhaseStudent phaseStudent=baseMapper.selectPhaseStudentById(phaseStudentId);
         if(ObjectUtil.isNull(phaseStudent)){
-            throw new ApiException(String.format("该批次下不存在该学员<>",phaseStudent.getStudentName()));
+            throw new ApiException("该批次下不存在该学员id");
         }
         checkUserAllowed(phaseStudent);
         int studentStudyCount=studentStudyMapper.countByPhaseId(phaseStudent.getPhaseId(),phaseStudent.getStudentId());
@@ -171,13 +185,14 @@
         ExCoursePhase coursePhase= coursePhaseMapper.selectCoursePhaseById(phaseId);
         ExCompanyPeriod companyPeriod=new ExCompanyPeriod();
         companyPeriod.setPhaseId(phaseId);
-        companyPeriod.setModifyPeriod(-1*studentCount*coursePhase.getCoursePeriod());
+        companyPeriod.setModifyPeriod(-1L*studentCount*coursePhase.getCoursePeriod());
         companyPeriod.setOrigin("\""+coursePhase.getName()+"\"新增学员消耗");
         SysCompany company=companyService.getById(coursePhase.getCompanyId());
-        int remainPeriod=company.getTotalPeriod()+companyPeriod.getModifyPeriod();
+        Long remainPeriod=company.getRemainPeriod()+companyPeriod.getModifyPeriod();
         if(remainPeriod<0){
             throw new ApiException("企业剩余课时不足");
         }
+        companyPeriod.setCompanyId(company.getId());
         companyPeriod.setRemainPeriod(remainPeriod);
         companyPeriodService.save(companyPeriod);
         company.setRemainPeriod(companyPeriod.getRemainPeriod());
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 8b45914..85f7f18 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
@@ -69,6 +69,7 @@
             questionBank.setPrivatize(PrivatizeEnum.PUBLIC.getCode());
         }else{
             questionBank.setCompanyId(user.getCompanyId());
+            questionBank.setPrivatize(PrivatizeEnum.PRIVATE.getCode());
         }
         int row =baseMapper.insert(questionBank);
         if(row<1){
@@ -98,7 +99,7 @@
         if(currentUser.getUserType().equals(UserTypeEnum.STUDENT.getCode())){
             throw new ApiException("没有权限操作");
         }
-        if(!currentUser.getCompanyId().equals(questionBank.getCompanyId())){
+        if(questionBank.getCompanyId()!=null&&!currentUser.getCompanyId().equals(questionBank.getCompanyId())){
             throw new ApiException("没有权限操作其他企业课程");
         }
     }
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 809eabf..f083a6e 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
@@ -6,6 +6,7 @@
 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.PaperStudentStateEnum;
 import com.gkhy.exam.common.enums.PrivatizeEnum;
 import com.gkhy.exam.common.enums.QuestionTypeEnum;
 import com.gkhy.exam.common.enums.UserTypeEnum;
@@ -25,9 +26,12 @@
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 
 /**
  * <p>
@@ -48,17 +52,21 @@
 
     @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("无权限查看其它企业题目");
-                }
-            }
+//        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("无权限查看其它企业题目");
+//                }
+//            }
+//        }
+        SysUser currentUser=SecurityUtils.getLoginUser().getUser();
+        if(!currentUser.getUserType().equals(UserTypeEnum.SYSTEM_USER.getCode())){
+            question.setCompanyId(currentUser.getCompanyId());
         }
         PageUtils.startPage();
         List<ExQuestion> questionList=baseMapper.selectQuestionList(question);
@@ -67,7 +75,7 @@
 
     @Override
     public ExQuestion selectQuestionById(Long questionId) {
-        ExQuestion question= baseMapper.selectById(questionId);
+        ExQuestion question= baseMapper.selectByQuestionId(questionId);
         if(question.getPrivatize().equals(PrivatizeEnum.PUBLIC.getCode())){
             return question;
         }
@@ -85,15 +93,22 @@
     public int insertQuestion(ExQuestion question) {
         checkUserAllowed(question);
         SysUser user= SecurityUtils.getLoginUser().getUser();
+        int totalCount=questionBankMapper.selectCountByBankId(question.getBankId());
+        if(totalCount>1000){
+            throw new ApiException("题库题目数量超过1000,不能再新增");
+        }
         //公开的题库新增题目,题目也是公开
         ExQuestionBank questionBank=questionBankMapper.selectById(question.getBankId());
-        if(user.getUserType().equals(UserTypeEnum.SYSTEM_USER.getCode())||questionBank.getPrivatize().equals(PrivatizeEnum.PUBLIC.getCode())){
+        if(user.getUserType().equals(UserTypeEnum.SYSTEM_USER.getCode())&&questionBank.getPrivatize().equals(PrivatizeEnum.PRIVATE.getCode())){
+            throw new ApiException("管理员不允许在私有题库创建题目");
+        }else if (user.getUserType().equals(UserTypeEnum.SYSTEM_USER.getCode())&&questionBank.getPrivatize().equals(PrivatizeEnum.PUBLIC.getCode())){
             question.setPrivatize(PrivatizeEnum.PUBLIC.getCode());
         }else{
             question.setCompanyId(user.getCompanyId());
             question.setPrivatize(PrivatizeEnum.PRIVATE.getCode());
         }
         validData(question);
+        question.setCreateBy(user.getUsername());
         int row=baseMapper.insert(question);
         if(row<1){
             throw new ApiException("新增题目失败");
@@ -105,6 +120,7 @@
     public int updateQuestion(ExQuestion question) {
         validData(question);
         checkUserAllowed(question);
+        question.setUpdateBy(SecurityUtils.getUsername());
         int row=baseMapper.updateById(question);
         if(row<1){
             throw new ApiException("编辑题目失败");
@@ -113,7 +129,7 @@
     }
 
     public void validData(ExQuestion question){
-        if(!question.getQuestionType().equals(QuestionTypeEnum.JUDGE.getCode())){
+        if(!question.getQuestionType().equals(QuestionTypeEnum.JUDGE.getCode())&&!question.getQuestionType().equals(QuestionTypeEnum.EASY.getCode())){
             if(StringUtils.isBlank(question.getContent())){
                 throw new ApiException("题目内容不能为空");
             }
@@ -141,7 +157,7 @@
         if(currentUser.getUserType().equals(UserTypeEnum.STUDENT.getCode())){
             throw new ApiException("没有权限操作");
         }
-        if(!currentUser.getCompanyId().equals(question.getCompanyId())){
+        if(question.getCompanyId()!=null&&!currentUser.getCompanyId().equals(question.getCompanyId())){
             throw new ApiException("没有权限操作其他企业题目");
         }
     }
@@ -153,8 +169,8 @@
     }
 
     @Override
-    public List<Map> getExerciseQuestionList(Long bankId, Integer exerciseType) {
-        return baseMapper.getExerciseQuestionList(bankId,exerciseType,SecurityUtils.getUserId());
+    public List<Map> getExerciseQuestionList(Long bankId) {
+        return baseMapper.getExerciseQuestionList(bankId,SecurityUtils.getUserId());
     }
 
     @Override
@@ -164,6 +180,12 @@
 
     @Override
     public List<ExQuestion> getExerciseQuestionByIds(List<Long> questionIds) {
+        if(questionIds==null|| questionIds.isEmpty()){
+            throw new ApiException("题目id列表不能为空");
+        }
+        if(questionIds.size()>30){
+            throw new ApiException("批量id数量超过阀值");
+        }
         return baseMapper.getExeriseQuestionByIds(questionIds,SecurityUtils.getUserId());
     }
 
@@ -176,28 +198,46 @@
         if(paperStudent==null){
             throw new ApiException("您分配的试卷未查询到");
         }
+        Long currentDateTime=System.currentTimeMillis();
         if(viewType==1){//更新考试开始时间
-            Long startTime=System.currentTimeMillis();
-            if(paperStudent.getCompleted()==1){
+            if(paperStudent.getState()!= PaperStudentStateEnum.WAIT_EXAM.getCode()){
                 throw new ApiException("考试已完成,不能重复考试");
             }
-            if(paperStudent.getStartTime()!=null) {//判断考卷是否已完成
-                ExExamPaper examPaper = examPaperMapper.selectById(paperStudent.getPaperId());
-                if(examPaper.getLimit()==1) {
-                    Long currentDateTime = System.currentTimeMillis();
-                    if (currentDateTime-paperStudent.getStartTime()>=examPaper.getLimitTime()*60*1000){
-                        paperStudent.setCompleted(1);
-                        paperStudentMapper.updateById(paperStudent);
-                        throw new ApiException("考试已超时,不能再考试");
-                    }
+            ExExamPaper examPaper = examPaperMapper.selectById(paperStudent.getPaperId());
+            if(examPaper.getLimited()==1){
+                if(paperStudent.getStartTime()!=null && (currentDateTime-paperStudent.getStartTime()>=examPaper.getLimitTime()*60*1000)){
+//                    paperStudent.setCompleted(1);
+//                    paperStudentMapper.updateById(paperStudent);
+                    throw new ApiException("考试已超时,不能再考试");
+                }
+                LocalDateTime deadline = examPaper.getDeadline();
+                if(currentDateTime-deadline.toInstant(ZoneOffset.of("+8")).toEpochMilli()>0){
+//                    paperStudent.setCompleted(1);
+//                    paperStudentMapper.updateById(paperStudent);
+                    throw new ApiException("已过考试截止时间,不能再考试");
                 }
             }
-            int row=paperStudentMapper.updateById(new ExPaperStudent().setPaperId(paperStudent.getPaperId()).setStudentId(paperStudent.getStudentId()).setStartTime(startTime));
-            if(row<1){
-                throw new ApiException("设置考试开始时间失败");
+            if(paperStudent.getStartTime()==null) {
+                int row = paperStudentMapper.updateById(new ExPaperStudent().setId(paperStudent.getId()).setPaperId(paperStudent.getPaperId()).setStudentId(paperStudent.getStudentId()).setStartTime(currentDateTime));
+                if (row < 1) {
+                    throw new ApiException("设置考试开始时间失败");
+                }
+            }
+        }else{
+            if(!Objects.equals(paperStudent.getState(), PaperStudentStateEnum.DONE_REVIEW.getCode())){
+//                if(paperStudent.getStartTime()!=null) {//判断考卷是否已完成
+//                    ExExamPaper examPaper = examPaperMapper.selectById(paperStudent.getPaperId());
+//                    if(examPaper.getLimited()==1) {
+//                        if (currentDateTime-paperStudent.getStartTime()>=examPaper.getLimitTime()*60*1000){
+//                            paperStudent.setCompleted(1);
+//                            paperStudentMapper.updateById(paperStudent);
+//                        }
+//                    }
+//                }
+                throw new ApiException("试卷未审批完,无法查看");
             }
         }
-        return baseMapper.getPaperQuestionList(paperId,paperStudent.getCompleted(),SecurityUtils.getUserId());
+        return baseMapper.getPaperQuestionList(paperId,paperStudent.getState(),SecurityUtils.getUserId(),viewType);
     }
 
     @Override
@@ -209,11 +249,14 @@
         if(paperStudent==null){
             throw new ApiException("您分配的试卷未查询到");
         }
-        return baseMapper.getPaperQuestionById(paperId,questionId,paperStudent.getCompleted(),SecurityUtils.getUserId());
+        return baseMapper.getPaperQuestionById(paperId,questionId,paperStudent.getState(),SecurityUtils.getUserId());
     }
 
     @Override
     public List<ExQuestion> getPaperQuestionByIds(Long paperId, List<Long> questionIds) {
+        if(questionIds.size()>30){
+            throw new ApiException("批量id数量超过阀值");
+        }
         LambdaQueryWrapper<ExPaperStudent> lambdaQueryWrapper = Wrappers.<ExPaperStudent>lambdaQuery()
                 .eq(ExPaperStudent::getPaperId, paperId)
                 .eq(ExPaperStudent::getStudentId, SecurityUtils.getUserId());
@@ -221,11 +264,16 @@
         if(paperStudent==null){
             throw new ApiException("您分配的试卷未查询到");
         }
-        return baseMapper.getPaperQuestionByIds(paperId,questionIds,paperStudent.getCompleted(),SecurityUtils.getUserId());
+        return baseMapper.getPaperQuestionByIds(paperId,questionIds,paperStudent.getState(),SecurityUtils.getUserId());
     }
 
     @Override
     public List<Long> getExerciseErrorQuestionList(Long bankId) {
         return baseMapper.getExerciseErrorQuestionList(bankId,SecurityUtils.getUserId());
     }
+
+    @Override
+    public List<ExQuestion> selectQuestionByPaperId(Long paperId) {
+        return baseMapper.selectQuestionByPaperId(paperId);
+    }
 }
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 452ec96..200e266 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
@@ -2,6 +2,7 @@
 
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.gkhy.exam.common.api.CommonPage;
+import com.gkhy.exam.common.config.MinioConfig;
 import com.gkhy.exam.common.constant.UserConstant;
 import com.gkhy.exam.common.domain.entity.SysUser;
 import com.gkhy.exam.common.enums.PrivatizeEnum;
@@ -32,6 +33,12 @@
 public class ExResourceServiceImpl extends ServiceImpl<ExResourceMapper, ExResource> implements ExResourceService {
     @Autowired
     private SysCommonService commonService;
+
+    @Autowired
+    private MinioConfig minioConfig;
+
+
+
     @Override
     public CommonPage selectResourseList(ExResource resource) {
         SysUser currentUser = SecurityUtils.getLoginUser().getUser();
@@ -40,6 +47,9 @@
         }
         PageUtils.startPage();
         List<ExResource> resourceList=baseMapper.selectResourceList(resource);
+        resourceList.forEach(item -> {
+            item.setResourcePath(minioConfig.getEndpoint()+minioConfig.getBucketName()+"/"+item.getResourcePath());
+        });
         return CommonPage.restPage(resourceList);
     }
 
@@ -49,6 +59,7 @@
         if(resource==null){
             return resource;
         }
+        resource.setResourcePath(minioConfig.getEndpoint()+minioConfig.getBucketName()+"/"+resource.getResourcePath());
         if(resource.getPrivatize().equals(PrivatizeEnum.PUBLIC.getCode())){
             return resource;
         }
@@ -59,6 +70,7 @@
         if(!resource.getCompanyId().equals(currentUser.getCompanyId())){
             throw new ApiException("无权限查看其它企业资源");
         }
+
         return resource;
     }
 
@@ -68,6 +80,7 @@
         if(resource==null){
             return resource;
         }
+        resource.setResourcePath(minioConfig.getEndpoint()+minioConfig.getBucketName()+"/"+resource.getResourcePath());
         if(resource.getPrivatize().equals(PrivatizeEnum.PUBLIC.getCode())){
             return resource;
         }
@@ -126,6 +139,11 @@
         if(!checkNameUnique(resource)){
             throw new ApiException("资源名称已存在");
         }
+        String resourcePath=resource.getResourcePath();
+        if(resourcePath.startsWith(minioConfig.getEndpoint()+minioConfig.getBucketName()+"/")) {
+            resourcePath = resourcePath.replace(minioConfig.getEndpoint()+minioConfig.getBucketName() + "/", "");
+            resource.setResourcePath(resourcePath);
+        }
         int row=baseMapper.updateById(resource);
         if(row<1){
             throw new ApiException("更新资源失败");
@@ -141,7 +159,7 @@
         if(currentUser.getUserType().equals(UserTypeEnum.STUDENT.getCode())){
             throw new ApiException("没有权限操作");
         }
-        if(!currentUser.getCompanyId().equals(resource.getCompanyId())){
+        if(resource.getCompanyId()!=null&&!currentUser.getCompanyId().equals(resource.getCompanyId())){
             throw new ApiException("没有权限操作其他企业资源");
         }
     }
@@ -149,8 +167,12 @@
     @Override
     @Transactional(rollbackFor = RuntimeException.class)
     public int deleteResourceById(Long resourceId) {
-        //校验资源是否绑定
         checkUserAllowed(baseMapper.selectById(resourceId));
+        //校验资源是否绑定
+        int count= baseMapper.checkResourceAssign(resourceId);
+        if(count>0){
+            throw new ApiException("资源已跟课时关联,不能删除");
+        }
         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
index 14ae8db..c1e4783 100644
--- 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
@@ -33,17 +33,27 @@
         if(!user.getUserType().equals(UserTypeEnum.SYSTEM_USER.getCode())){
             companyId=user.getCompanyId();
         }
+        if(startTime==null && endTime==null){
+            endTime=new Date();
+            startTime=DateUtil.offsetDay(endTime,-7);
+        }else if(startTime!=null&&endTime==null){
+            endTime=DateUtil.offsetDay(startTime,7);
+        }else if(startTime==null&&endTime!=null){
+            startTime=DateUtil.offsetDay(endTime,-7);
+        }
         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);
+        if(companyList.size()>0) {
+            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);
@@ -51,14 +61,15 @@
             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()));
 
+        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);
@@ -73,11 +84,11 @@
             List<CompanyPhaseVO> companyPhaseVOs=companyPhaseVOMap.get(item.getId());
             if(companyPhaseVOs!=null&&companyPhaseVOs.size()>0){
                 companyPhaseVOs.forEach(cp -> {
-                    if(cp.getLevel().equals(PhaseLevelEnum.COMPANY)){
+                    if(cp.getLevel().equals(PhaseLevelEnum.COMPANY.getCode())){
                         companyStatisticVO.setLevel1PhaseCount(cp.getPhaseCount());
-                    }else if(cp.getLevel().equals(PhaseLevelEnum.DEPART)){
+                    }else if(cp.getLevel().equals(PhaseLevelEnum.DEPART.getCode())){
                         companyStatisticVO.setLevel2PhaseCount(cp.getPhaseCount());
-                    }else if(cp.getLevel().equals(PhaseLevelEnum.WORkSHOP)) {
+                    }else if(cp.getLevel().equals(PhaseLevelEnum.WORkSHOP.getCode())) {
                         companyStatisticVO.setLevel3PhaseCount(cp.getPhaseCount());
                     }
                 });
@@ -86,11 +97,11 @@
             List<CompanyPhaseStudentVO> companyPhaseStudentVOs=companyPhaseStudentVOMap.get(item.getId());
             if(companyPhaseStudentVOs!=null&&companyPhaseStudentVOs.size()>0){
                 companyPhaseStudentVOs.forEach(cp -> {
-                    if(cp.getLevel().equals(PhaseLevelEnum.COMPANY)){
+                    if(cp.getLevel().equals(PhaseLevelEnum.COMPANY.getCode())){
                         companyStatisticVO.setLevel1StudentCount(cp.getPhaseStudentCount());
-                    }else if(cp.getLevel().equals(PhaseLevelEnum.DEPART)){
+                    }else if(cp.getLevel().equals(PhaseLevelEnum.DEPART.getCode())){
                         companyStatisticVO.setLevel2StudentCount(cp.getPhaseStudentCount());
-                    }else if(cp.getLevel().equals(PhaseLevelEnum.WORkSHOP)) {
+                    }else if(cp.getLevel().equals(PhaseLevelEnum.WORkSHOP.getCode())) {
                         companyStatisticVO.setLevel3StudentCount(cp.getPhaseStudentCount());
                     }
                 });
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExStudentAnswerServiceImpl.java b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExStudentAnswerServiceImpl.java
index 775123e..e99ed18 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExStudentAnswerServiceImpl.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExStudentAnswerServiceImpl.java
@@ -1,9 +1,9 @@
 package com.gkhy.exam.system.service.impl;
 
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.gkhy.exam.common.enums.PaperStudentStateEnum;
 import com.gkhy.exam.common.exception.ApiException;
 import com.gkhy.exam.system.domain.ExPaperStudent;
-import com.gkhy.exam.system.domain.ExQuestion;
 import com.gkhy.exam.system.domain.ExStudentAnswer;
 import com.gkhy.exam.system.mapper.ExPaperStudentMapper;
 import com.gkhy.exam.system.mapper.ExQuestionMapper;
@@ -11,6 +11,8 @@
 import com.gkhy.exam.system.service.ExStudentAnswerService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+
+import java.util.Objects;
 
 /**
  * <p>
@@ -30,12 +32,18 @@
     public int addStudentAnswer(ExStudentAnswer studentAnswer) {
         int row=0;
         validData(studentAnswer);
-        ExQuestion question=questionMapper.selectById(studentAnswer.getQuestionId());
-        if(studentAnswer.getAnswer().equals(question.getAnswer())){
-            studentAnswer.setPassed(1);
-        }else{
-            studentAnswer.setPassed(0);
-        }
+//        ExQuestion question=questionMapper.selectById(studentAnswer.getQuestionId());
+//        if(question.getQuestionType().equals(QuestionTypeEnum.EASY.getCode())){
+//            studentAnswer.setPassed(StudentAnswerPassEnum.WAIT_REVIEW.getCode());
+//        }else{
+//            if(studentAnswer.getAnswer().equals(question.getAnswer())){
+//                studentAnswer.setPassed(StudentAnswerPassEnum.CORRECT.getCode());
+//                studentAnswer.setScore();
+//            }else{
+//                studentAnswer.setPassed(StudentAnswerPassEnum.ERROR.getCode());
+//                studentAnswer.setScore(0);
+//            }
+//        }
         ExStudentAnswer existAnswer= baseMapper.getStudentAnswer(studentAnswer);
         if(existAnswer!=null){
             studentAnswer.setId(existAnswer.getId());
@@ -51,7 +59,7 @@
 
     public void validData(ExStudentAnswer studentAnswer){
         ExPaperStudent paperStudent=paperStudentMapper.selectByPaperStudentId(new ExPaperStudent().setPaperId(studentAnswer.getPaperId()).setStudentId(studentAnswer.getStudentId()));
-        if(paperStudent.getCompleted()==1){
+        if(!Objects.equals(paperStudent.getState(), PaperStudentStateEnum.WAIT_EXAM.getCode())){
             throw new ApiException("考试已完成,不能再作答");
         }
 
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 67ca293..15d920a 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
@@ -12,16 +12,24 @@
 import com.gkhy.exam.common.utils.PageUtils;
 import com.gkhy.exam.common.utils.RedisUtils;
 import com.gkhy.exam.common.utils.SecurityUtils;
+import com.gkhy.exam.common.utils.StringUtils;
+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.domain.SysCompany;
+import com.gkhy.exam.system.domain.vo.TrainRecordVO;
+import com.gkhy.exam.system.mapper.ExPaperStudentMapper;
+import com.gkhy.exam.system.mapper.ExPhaseStudentMapper;
 import com.gkhy.exam.system.mapper.ExStudentMapper;
+import com.gkhy.exam.system.mapper.SysUserMapper;
 import com.gkhy.exam.system.service.ExStudentService;
 import com.gkhy.exam.system.service.SysCompanyService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
-import java.util.List;
+import java.util.*;
 import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
 
 /**
  * <p>
@@ -37,12 +45,34 @@
     private SysCompanyService companyService;
     @Autowired
     private RedisUtils redisUtils;
+    @Autowired
+    private ExPhaseStudentMapper phaseStudentMapper;
+    @Autowired
+    private ExPaperStudentMapper paperStudentMapper;
+    @Autowired
+    private SysUserMapper userMapper;
 
     @Override
     public CommonPage selectStudentList(ExStudent student) {
         SysUser currentUser= SecurityUtils.getLoginUser().getUser();
         if(!currentUser.getUserType().equals(UserTypeEnum.SYSTEM_USER.getCode())){
             student.setCompanyId(currentUser.getCompanyId());
+            Map<String,Object> paramsMap=new HashMap<>();
+            if(currentUser.getUserType().equals(UserTypeEnum.DEPART_USER.getCode())) {//部门级用户
+                List<Long> workshopUserIds=userMapper.selectWorkshopUserIds(currentUser.getId());
+                if(workshopUserIds==null){
+                    workshopUserIds=new ArrayList<>();
+                }
+                workshopUserIds.add(currentUser.getId());
+                paramsMap.put("createIds",workshopUserIds);
+                student.setParams(paramsMap);
+            }else if(currentUser.getUserType().equals(UserTypeEnum.WORKSHOP_USER.getCode())){//车间级用户
+                List<Long> workshopUserIds=new ArrayList<>();
+                workshopUserIds.add(currentUser.getId());
+                workshopUserIds.add(currentUser.getParentId());
+                paramsMap.put("createIds",workshopUserIds);
+                student.setParams(paramsMap);
+            }
         }
         PageUtils.startPage();
         List<ExStudent> studentList=baseMapper.selectStudentList(student);
@@ -73,6 +103,10 @@
         SysUser currentUser=SecurityUtils.getLoginUser().getUser();
         if(currentUser.getUserType().equals(UserTypeEnum.SYSTEM_USER.getCode())){
             return student;
+        }else if (currentUser.getUserType().equals(UserTypeEnum.STUDENT.getCode())){
+            if(!Objects.equals(studentId, currentUser.getId())){
+                throw new ApiException("无权查看其它学员信息");
+            }
         }
         if(!student.getCompanyId().equals(currentUser.getCompanyId())){
             throw new ApiException("无权限查看其它企业学员");
@@ -84,6 +118,7 @@
     @Override
     public int insertStudent(ExStudent student) {
         SysUser currentUser= SecurityUtils.getLoginUser().getUser();
+        student.setCompanyId(currentUser.getCompanyId());
         checkUserAllowed(student);
         if(!checkPhoneUnique(student)){
             throw new ApiException("手机号已存在");
@@ -91,7 +126,19 @@
         if(!checkIdNoUnique(student)){
             throw new ApiException("身份证号已存在");
         }
-        student.setCreateId(currentUser.getId());
+        if(currentUser.getUserType().equals(UserTypeEnum.COMPANY_USER.getCode())){
+            if(student.getCreateId()==null){
+                throw new ApiException("部门id为空");
+            }
+        }else if(currentUser.getUserType().equals(UserTypeEnum.DEPART_USER.getCode())){
+            student.setCreateId(currentUser.getId());
+        }else{//当前用户为车间级用户
+            if(currentUser.getParentId()==null){
+                throw new ApiException("当前用户部门id为空");
+            }
+            student.setCreateId(currentUser.getParentId());
+        }
+        student.setPassword(SecurityUtils.encryptPassword(Base64.decodeStr(student.getPassword())));
         int row=baseMapper.insert(student);
         if(row<0){
             throw new ApiException("新增学员失败");
@@ -109,6 +156,7 @@
             throw new ApiException("身份证号已存在");
         }
         ExStudent existStudent=checkUserDataScope(student.getId());
+        student.setPassword(null);
         int row=baseMapper.updateById(student);
         if(row<0){
             throw new ApiException("更新学员失败");
@@ -150,13 +198,30 @@
     }
 
     @Override
-    public ExStudent checkIdNoUnique(String idNo) {
-        ExStudent stu= baseMapper.checkIdNoUnique(idNo);
-        if(stu!=null){
-            SysCompany company=companyService.selectCompanyById(stu.getCompanyId());
-            stu.setCompany(company);
+    public Map checkIdNoUnique(String idNo) {
+        if(StringUtils.isBlank(idNo)){
+            throw new ApiException("身份证号不能为空");
         }
-        return stu;
+        SysUser currentUser=SecurityUtils.getLoginUser().getUser();
+        ExStudent stu= baseMapper.checkIdNoUnique(idNo);
+        Map<String,Object> resMap=new HashMap<>();
+        Integer status=0;//默认不存在
+        if(stu!=null){
+            status=1; //存在,且同一个公司
+            resMap.put("studentId",stu.getId());
+            resMap.put("studentName",stu.getName());
+            if(stu.getCompanyId()!=currentUser.getCompanyId()){
+                status=2;  //存在,不同公司
+                SysCompany company=companyService.selectCompanyById(stu.getCompanyId());
+                if(company==null){
+                    throw new ApiException("学员公司不存在");
+                }
+                resMap.put("companyId",company.getId());
+                resMap.put("companyName",company.getName());
+            }
+        }
+        resMap.put("status",status);
+        return resMap;
     }
 
     @Override
@@ -167,6 +232,62 @@
         su.setUpdateBy(SecurityUtils.getUsername());
         delCacheByPhone(existStudent.getPhone());
         return updateById(su);
+    }
+
+    @Override
+    public void changeStudentCompany(Map<String, Long> bodyMap) {
+        Long studentId=bodyMap.get("studentId");
+        Long companyId=bodyMap.get("companyId");
+        if(studentId==null||companyId==null){
+            throw new ApiException("学员id或者公司id不能为空");
+        }
+        ExStudent student = baseMapper.selectById(studentId);
+        if(student==null){
+            throw new ApiException("学员不存在");
+        }
+        SysCompany company=companyService.selectCompanyById(companyId);
+        if(company==null){
+            throw new ApiException("公司不存在");
+        }
+        ExStudent stu=new ExStudent().setId(studentId).setCompanyId(companyId);
+        stu.setUpdateBy(SecurityUtils.getUsername());
+        baseMapper.updateById(stu);
+    }
+
+    @Override
+    public List<TrainRecordVO> trainRecord(Long studentId) {
+        List<TrainRecordVO> trainRecordVOList=new ArrayList<>();
+        //查询培训记录
+        List<ExPhaseStudent> phaseStudentList=phaseStudentMapper.selectPhaseStudentByStudentId(studentId);
+        if(phaseStudentList.size()>0){
+            trainRecordVOList.addAll(phaseStudentList.stream().map(item -> {
+                TrainRecordVO trainRecordVO=new TrainRecordVO();
+                trainRecordVO.setStudentId(item.getStudentId());
+                trainRecordVO.setTrainType(1);
+                trainRecordVO.setName(item.getPhaseName());
+                trainRecordVO.setCreateTime(item.getCreateTime());
+                trainRecordVO.setCompanyId(item.getCompanyId());
+                trainRecordVO.setCompanyName(item.getCompanyName());
+                return trainRecordVO;
+            }).collect(Collectors.toList()));
+        }
+        //查询考试记录
+        List<ExPaperStudent> paperStudentList=paperStudentMapper.selectByStudentId(studentId);
+        if(paperStudentList.size()>0){
+            trainRecordVOList.addAll(paperStudentList.stream().map(item -> {
+                TrainRecordVO trainRecordVO=new TrainRecordVO();
+                trainRecordVO.setStudentId(item.getStudentId());
+                trainRecordVO.setTrainType(2);
+                trainRecordVO.setName(item.getExamPaper().getName());
+                trainRecordVO.setCreateTime(item.getCreateTime());
+                trainRecordVO.setCompanyId(item.getCompanyId());
+                trainRecordVO.setCompanyName(item.getCompanyName());
+                return trainRecordVO;
+            }).collect(Collectors.toList()));
+        }
+        //排序
+        trainRecordVOList=trainRecordVOList.stream().sorted(Comparator.comparing(TrainRecordVO::getCreateTime)).collect(Collectors.toList());;
+        return trainRecordVOList;
     }
 
     public ExStudent checkUserDataScope(Long studentId) {
@@ -183,13 +304,27 @@
 
     public void checkUserAllowed(ExStudent student) {
         SysUser currentUser= SecurityUtils.getLoginUser().getUser();
-        if(currentUser.getUserType().equals(UserTypeEnum.SYSTEM_USER.getCode())){
-            throw new ApiException("系统管理员没有权限操作");
+        if(student.getId()!=null){
+            if(currentUser.getUserType().equals(UserTypeEnum.SYSTEM_USER.getCode())){
+                return;
+            }
+            if(currentUser.getUserType().equals(UserTypeEnum.STUDENT.getCode()) ){
+                if(!Objects.equals(currentUser.getId(), student.getId())){
+                    throw new ApiException("没有权限操作");
+                }else{
+                    return;
+                }
+            }
+        }else{
+            if(currentUser.getUserType().equals(UserTypeEnum.SYSTEM_USER.getCode())){
+                throw new ApiException("系统管理员没有权限操作");
+            }
+            if(currentUser.getUserType().equals(UserTypeEnum.STUDENT.getCode())){
+                throw new ApiException("没有权限操作");
+            }
         }
-        if(currentUser.getUserType().equals(UserTypeEnum.STUDENT.getCode())){
-            throw new ApiException("没有权限操作");
-        }
-        if(!currentUser.getCompanyId().equals(student.getCompanyId())){
+
+        if(student.getCompanyId()!=null&&!currentUser.getCompanyId().equals(student.getCompanyId())){
             throw new ApiException("没有权限操作其他企业学员");
         }
     }
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExStudentStudyServiceImpl.java b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExStudentStudyServiceImpl.java
index 05217ea..428e5ee 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExStudentStudyServiceImpl.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/ExStudentStudyServiceImpl.java
@@ -51,10 +51,11 @@
             row=baseMapper.updateById(existStudentStudy);
         }else{
             row=baseMapper.insert(studentStudy);
+            if(row<1){
+                throw new ApiException("新增学习记录失败");
+            }
         }
-        if(row<1){
-            throw new ApiException("新增学习记录失败");
-        }
+        System.out.println("student_study id:"+studentStudy.getId());
         return studentStudy.getId();
     }
 
@@ -82,6 +83,7 @@
                 studentStudyPeriodVO.setPeriodId(courseChapterPeriod.getId());
                 studentStudyPeriodVO.setPeriod(courseChapterPeriod.getPeriod());
                 studentStudyPeriodVO.setResourceId(courseChapterPeriod.getResourceId());
+                studentStudyPeriodVO.setResourceType(courseChapterPeriod.getResource()!=null?courseChapterPeriod.getResource().getResourceType():null);
                 ExStudentStudy exStudentStudy=studentStudyMap.get(courseChapterPeriod.getId());
                 if(exStudentStudy!=null){
                     studentStudyPeriodVO.setProgress(exStudentStudy.getProgress());
@@ -100,7 +102,7 @@
 
     @Override
     public void progress(ExStudentStudy studentStudy) {
-        if(studentStudy.getPhaseId()==null||studentStudy.getPeriodId()==null||studentStudy.getStudentId()==null||studentStudy.getResourceId()==null){
+        if(studentStudy.getId()==null||studentStudy.getPhaseId()==null||studentStudy.getPeriodId()==null||studentStudy.getStudentId()==null||studentStudy.getResourceId()==null){
             throw new ApiException("参数传参错误");
         }
         ExResource resource=resourceMapper.selectById(studentStudy.getResourceId());
@@ -112,10 +114,12 @@
             }
         } else if (ResourceTypeEnum.DOC.getCode().equals(resource.getResourceType())) {
             // 文档类型处理
-            if (studentStudy.getCurrentPage().compareTo(resource.getDocPage()) >= 0) {
-                // 学习完成
-                 completeStudy(studentStudy);
-            }
+//            if (studentStudy.getCurrentPage().compareTo(resource.getDocPage()) >= 0) {
+//                // 学习完成
+//                 completeStudy(studentStudy);
+//            }
+            // 学习完成
+            completeStudy(studentStudy);
         }
         redisUtils.set(CacheConstant.STUDY_PROCESS_KEY + studentStudy.getId(), studentStudy, 1, TimeUnit.DAYS);
     }
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/service/impl/SysCarouselServiceImpl.java b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/SysCarouselServiceImpl.java
index 21ae563..09fb422 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/service/impl/SysCarouselServiceImpl.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/SysCarouselServiceImpl.java
@@ -24,9 +24,9 @@
 
     @Override
     public CommonPage selectCarouselList(SysCarousel carousel) {
-        PageUtils.startPage();
-        List<SysCarousel> carousels=baseMapper.selectCarouselList(carousel);
-        return CommonPage.restPage(carousels);
+            PageUtils.startPage();
+            List<SysCarousel> carousels = baseMapper.selectCarouselList(carousel);
+            return CommonPage.restPage(carousels);
     }
 
     @Override
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/service/impl/SysCategoryServiceImpl.java b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/SysCategoryServiceImpl.java
index 88e5f5a..f2e63da 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/service/impl/SysCategoryServiceImpl.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/SysCategoryServiceImpl.java
@@ -7,8 +7,11 @@
 import com.gkhy.exam.common.exception.ApiException;
 import com.gkhy.exam.common.utils.SecurityUtils;
 import com.gkhy.exam.system.domain.SysCategory;
+import com.gkhy.exam.system.mapper.ExCourseMapper;
+import com.gkhy.exam.system.mapper.ExQuestionBankMapper;
 import com.gkhy.exam.system.mapper.SysCategoryMapper;
 import com.gkhy.exam.system.service.SysCategoryService;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import java.util.Comparator;
@@ -26,6 +29,10 @@
  */
 @Service
 public class SysCategoryServiceImpl extends ServiceImpl<SysCategoryMapper, SysCategory> implements SysCategoryService {
+    @Autowired
+    private ExCourseMapper courseMapper;
+    @Autowired
+    private ExQuestionBankMapper questionBankMapper;
 
     @Override
     public List<SysCategory> selectCategoryList(SysCategory category) {
@@ -82,15 +89,15 @@
     public int deleteCategoryById(Long categoryId) {
         //校验课程分类是否存在课程或者题目
         checkUserAllowed();
-        int courseCount=baseMapper.selectCountOfCoure(categoryId);
+        int courseCount=courseMapper.selectCountByCategoryId(categoryId);
         if(courseCount>0){
             throw new ApiException("已绑定课程,无法删除");
         }
-        int bankCount=baseMapper.selectCountOfBank(categoryId);
+        int bankCount=questionBankMapper.selectCountByCategoryId(categoryId);
         if(bankCount>0){
             throw new ApiException("已绑定题库,无法删除");
         }
-        int row=baseMapper.deleteById(categoryId);
+        int row=baseMapper.deleteByCategoryId(categoryId);
         if(row<1){
             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 2ee2b25..9d8f52d 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
@@ -2,22 +2,35 @@
 
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.io.FileUtil;
+import com.alibaba.excel.EasyExcel;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.gkhy.exam.common.config.FilePathConfig;
+import com.gkhy.exam.common.config.MinioConfig;
+import com.gkhy.exam.common.domain.entity.SysUser;
 import com.gkhy.exam.common.enums.ResourceTypeEnum;
+import com.gkhy.exam.common.enums.UserTypeEnum;
+import com.gkhy.exam.common.excel.StudentExcelData;
+import com.gkhy.exam.common.excel.StudentExcelDataListener;
 import com.gkhy.exam.common.exception.ApiException;
 import com.gkhy.exam.common.utils.*;
 import com.gkhy.exam.system.domain.ExResource;
+import com.gkhy.exam.system.domain.ExStudent;
+import com.gkhy.exam.system.domain.SysCompany;
 import com.gkhy.exam.system.domain.vo.UploadObjectVO;
 import com.gkhy.exam.system.mapper.ExResourceMapper;
+import com.gkhy.exam.system.service.ExStudentService;
 import com.gkhy.exam.system.service.SysCommonService;
+import com.gkhy.exam.system.service.SysCompanyService;
+import com.gkhy.exam.system.service.SysUserService;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.io.FileUtils;
+import org.springframework.beans.BeanUtils;
 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.transaction.annotation.Transactional;
 import org.springframework.util.CollectionUtils;
 import org.springframework.web.multipart.MultipartFile;
 import sun.misc.BASE64Decoder;
@@ -33,6 +46,9 @@
 @Slf4j
 public class SysCommonServiceImpl implements SysCommonService {
 
+    @Autowired
+    private MinioConfig minioConfig;
+
     @Value("${image.upload_image}")
     private String uploadPath;
     @Autowired
@@ -43,9 +59,15 @@
     private ExResourceMapper resourceMapper;
     @Resource
     private FilePathConfig filePathConfig;
+    @Autowired
+    private SysCompanyService companyService;
+    @Autowired
+    private ExStudentService studentService;
+    @Autowired
+    private SysUserService userService;
 
     // 使用HashSet存储允许的文件格式,提高查找效率
-    private final HashSet<String> FORMATSET = new HashSet<>(Arrays.asList(".mp4", ".mp3", ".xls", ".xlsx", ".doc", ".docx", ".ppt", ".pptx", ".pdf"));
+    private final HashSet<String> FORMATSET = new HashSet<>(Arrays.asList(".mp4",".doc", ".docx", ".ppt", ".pptx", ".pdf"));
 
 
     @Resource(name = "threadPoolTaskExecutor")
@@ -202,6 +224,7 @@
             log.warn("临时目录 {}已删除", new File(localPath).getParent());
         });
         uploadObjectVO.setPath(minioPath);
+        uploadObjectVO.setUrl(minioConfig.getEndpoint()+minioConfig.getBucketName()+"/"+minioPath);
         return uploadObjectVO;
     }
 
@@ -236,6 +259,87 @@
         }
     }
 
+    @Override
+    @Transactional(rollbackFor = RuntimeException.class)
+    public void importStudent() {
+        String path="/home/java/train_exam/back/安全教育学员模板.xlsx";
+      //  String path="F:/kzy/乱七八糟/安全教育学员模板.xlsx";
+        List<StudentExcelData> studentExcelDataList=EasyExcel.read(path, StudentExcelData.class,new StudentExcelDataListener()).sheet().doReadSync();
+        List<ExStudent> students=new ArrayList<>();
+        List<StudentExcelData> errorStudents=new ArrayList<>();
+        SysCompany company=companyService.getOne(Wrappers.<SysCompany>lambdaQuery().eq(SysCompany::getName,studentExcelDataList.get(0).getCompanyName())
+                .eq(SysCompany::getDelFlag,0));
+        if(company==null){
+            throw new ApiException("公司不存在");
+        }
+        for(StudentExcelData studentExcelData:studentExcelDataList){
+            String errorMessage=validateData(studentExcelData);
+            if(StringUtils.isNotBlank(errorMessage)){
+                studentExcelData.setRemark(errorMessage);
+                errorStudents.add(studentExcelData);
+                continue;
+            }
+            ExStudent dbStudent=studentService.getOne(Wrappers.<ExStudent>lambdaQuery().eq(ExStudent::getPhone,studentExcelData.getPhone()));
+            if(dbStudent!=null){
+                if(!dbStudent.getName().equals(studentExcelData.getName())){
+                    studentExcelData.setRemark("序号"+studentExcelData.getIndex()+"学员用户已存在");
+                    errorStudents.add(studentExcelData);
+                }
+                continue;
+            }
+            ExStudent student=new ExStudent();
+            BeanUtils.copyProperties(studentExcelData,student,new String[]{"sex"});
+            if("男".equals(studentExcelData.getSex())){
+                student.setSex(0);
+            }else{
+                student.setSex(1);
+            }
+            String departName=studentExcelData.getDeptName();
+
+            List<SysUser> users=userService.list(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getName,departName).eq(SysUser::getUserType, UserTypeEnum.DEPART_USER.getCode()).eq(SysUser::getDelFlag,0).last(" limit 1"));
+            if(users.isEmpty()){
+                studentExcelData.setRemark("序号"+studentExcelData.getIndex()+"未找到相应的部门账号");
+                errorStudents.add(studentExcelData);
+                continue;
+            }
+
+            student.setPassword(SecurityUtils.encryptPassword("123456@a"));
+            student.setCompanyId(company.getId());
+            student.setCreateId(users.get(0).getId());
+            students.add(student);
+        }
+        if(!errorStudents.isEmpty()){
+            EasyExcel.write("error.xlsx").head(StudentExcelData.class)
+                    .sheet("异常用户列表")
+                    .doWrite(errorStudents);
+        }
+        studentService.saveBatch(students);
+    }
+
+
+
+
+
+    public String validateData(StudentExcelData studentExcelData){
+        if(StringUtils.isBlank(studentExcelData.getName())){
+            return "序号"+studentExcelData.getIndex()+"姓名为空";
+        }
+        if(StringUtils.isBlank(studentExcelData.getSex())){
+            return "序号"+studentExcelData.getIndex()+"性别为空";
+        }
+        if(StringUtils.isBlank(studentExcelData.getIdNo())||studentExcelData.getIdNo().length()!=18){
+            return "序号"+studentExcelData.getIndex()+"身份证为空或者长度不正确";
+        }
+        if(StringUtils.isBlank(studentExcelData.getPhone())||studentExcelData.getPhone().length()!=11){
+            return "序号"+studentExcelData.getIndex()+"手机号为空或者长度不正确";
+        }
+
+        if(StringUtils.isBlank(studentExcelData.getDeptName())){
+            return "序号"+studentExcelData.getIndex()+"部门为空";
+        }
+        return "";
+    }
+
     public UploadObjectVO mergeFile(String fileMd5,String fileName){
         String subfix = fileName.substring(fileName.lastIndexOf("."));
         String systemDir=System.getProperty("user.dir");
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/service/impl/SysCompanyServiceImpl.java b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/SysCompanyServiceImpl.java
index c140222..f412993 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/service/impl/SysCompanyServiceImpl.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/SysCompanyServiceImpl.java
@@ -49,6 +49,7 @@
             throw new ApiException("公司名称已存在");
         }
         company.setCreateBy(SecurityUtils.getUsername());
+        company.setRemainPeriod(company.getTotalPeriod());
         int row= baseMapper.insert(company);
         if(row<1){
             throw new ApiException("新增公司失败");
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/service/impl/SysUserServiceImpl.java b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/SysUserServiceImpl.java
index 899df46..b35568b 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/service/impl/SysUserServiceImpl.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/SysUserServiceImpl.java
@@ -9,7 +9,10 @@
 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.*;
+import com.gkhy.exam.common.utils.PageUtils;
+import com.gkhy.exam.common.utils.RedisUtils;
+import com.gkhy.exam.common.utils.SecurityUtils;
+import com.gkhy.exam.common.utils.StringUtils;
 import com.gkhy.exam.system.mapper.SysUserMapper;
 import com.gkhy.exam.system.service.SysConfigService;
 import com.gkhy.exam.system.service.SysUserService;
@@ -17,6 +20,7 @@
 import org.springframework.stereotype.Service;
 
 import javax.validation.Validator;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -44,14 +48,17 @@
     @Override
     public CommonPage<SysUser> selectUserList(SysUser user) {
         SysUser currentUser=SecurityUtils.getLoginUser().getUser();
-        Map<String,Object> paramsMap=new HashMap<>();
-        paramsMap.put("userType",currentUser.getUserType());
-        user.setParams(paramsMap);
-        if(!currentUser.getUserType().equals(UserTypeEnum.SYSTEM_USER.getCode())){
-            user.setCompanyId(currentUser.getCompanyId());
+        List<SysUser> users=new ArrayList<>();
+        if(!currentUser.getUserType().equals(UserTypeEnum.WORKSHOP_USER.getCode())){
+            if(!currentUser.getUserType().equals(UserTypeEnum.SYSTEM_USER.getCode())){
+                user.setCompanyId(currentUser.getCompanyId());
+                Map<String,Object> paramsMap=new HashMap<>();
+                paramsMap.put("userType",currentUser.getUserType());
+                user.setParams(paramsMap);
+            }
+            PageUtils.startPage();
+            users=baseMapper.userList(user);
         }
-        PageUtils.startPage();
-        List<SysUser> users=baseMapper.userList(user);
         return CommonPage.restPage(users);
     }
 
@@ -109,6 +116,7 @@
         checkRequestData(user);
         checkUserAllowed(user);
         user.setUpdateBy(SecurityUtils.getUsername());
+        user.setPassword(null);
         int row=baseMapper.updateById(user);
         if(row<1){
             throw new ApiException("更新用户信息失败");
@@ -182,7 +190,11 @@
         Integer currentUserType=currentUser.getUserType();
         Integer userType=user.getUserType();
         //校验权限,规则:上一级用户可以增加下一级用户类型的用户
-        if(!currentUserType.equals(UserTypeEnum.SYSTEM_USER.getCode())){
+        if(currentUserType.equals(UserTypeEnum.SYSTEM_USER.getCode())){
+            if( !userType.equals(UserTypeEnum.SYSTEM_USER.getCode())&&!userType.equals(UserTypeEnum.OTHER_USER.getCode()) &&!userType.equals(UserTypeEnum.COMPANY_USER.getCode())){
+                throw new ApiException("管理员只能操作管理员、企业级和其他类型的用户");
+            }
+        }else{
             if(userType.equals(UserTypeEnum.OTHER_USER.getCode())){
                 throw new ApiException("没有权限操作或者更新上级用户类型的用户");
             }
diff --git a/exam-system/src/main/resources/mapper/system/ExCourseChapterMapper.xml b/exam-system/src/main/resources/mapper/system/ExCourseChapterMapper.xml
index e552f0f..8ebafa9 100644
--- a/exam-system/src/main/resources/mapper/system/ExCourseChapterMapper.xml
+++ b/exam-system/src/main/resources/mapper/system/ExCourseChapterMapper.xml
@@ -40,6 +40,9 @@
         <result property="id"       column="resource_id"       />
         <result property="name"       column="resource_name"       />
         <result property="resourcePath"       column="resource_path"       />
+        <result property="resourceType"       column="resource_type"       />
+        <result property="resourceLength"       column="period"       />
+        <result property="docPage"       column="doc_page"       />
     </resultMap>
 
     <sql id="selectChapterVo">
@@ -85,8 +88,8 @@
     </select>
 
     <select id="getChapterPeriodByChapterId" resultMap="ExPeriodResult">
-        select a.id,a.name,a.course_id,a.chapter_id,a.status,a.company_id,a.resource_id,
-               b.resource_length as period,b.name as resource_name,b.resource_path from ex_course_chapter_period a
+        select a.id,a.name,a.course_id,a.chapter_id,a.status,a.company_id,a.resource_id,a.sort,
+               b.resource_length as period,b.name as resource_name,b.resource_path,b.doc_page,b.resource_type from ex_course_chapter_period a
         left join ex_resource b on b.id=a.resource_id
         where a.chapter_id=#{chapterId}
         <if test="status!=null">
diff --git a/exam-system/src/main/resources/mapper/system/ExCourseChapterPeriodMapper.xml b/exam-system/src/main/resources/mapper/system/ExCourseChapterPeriodMapper.xml
index daa8f1c..13ad48b 100644
--- a/exam-system/src/main/resources/mapper/system/ExCourseChapterPeriodMapper.xml
+++ b/exam-system/src/main/resources/mapper/system/ExCourseChapterPeriodMapper.xml
@@ -40,5 +40,9 @@
         select * from ex_course_chapter_period where chapter_id=#{chapterId}
     </select>
 
+    <select id="selectCountByCourseId" resultType="java.lang.Integer" parameterType="java.lang.Long">
+        select count(1) from ex_course_chapter_period where course_id=#{courseId} and status=0
+    </select>
+
 
 </mapper>
diff --git a/exam-system/src/main/resources/mapper/system/ExCourseMapper.xml b/exam-system/src/main/resources/mapper/system/ExCourseMapper.xml
index b66826a..70445b4 100644
--- a/exam-system/src/main/resources/mapper/system/ExCourseMapper.xml
+++ b/exam-system/src/main/resources/mapper/system/ExCourseMapper.xml
@@ -13,7 +13,7 @@
         <result property="delFlag"         column="del_flag"          />
         <result property="companyId"         column="company_id"          />
         <result property="privatize"         column="privatize"          />
-        <result property="period"         column="period"          />
+        <result property="message"         column="message"          />
         <result property="version"         column="version"          />
         <result property="createBy"       column="create_by"       />
         <result property="createTime"     column="create_time"     />
@@ -22,11 +22,12 @@
         <result property="remark"         column="remark"          />
         <result property="companyName"         column="company_name"          />
         <result property="categoryName"         column="category_name"          />
+        <association property="period" javaType="java.lang.Long"  select="getCoursePeriod" column="{courseId=id}"/>
     </resultMap>
 
     <sql id="selectCourseVo">
-        select a.id, a.name, a.category_id, a.status, a.logo,a.sort,a.introduce,a.state,a.company_id,
-               a.privatize,a.period,a.version, a.create_by, a.create_time, a.update_by, a.update_time, a.remark,b.name as company_name,c.name as category_name
+        select a.id, a.name, a.category_id, a.status, a.logo,a.sort,a.introduce,a.state,a.company_id,a.message,
+               a.privatize,a.version, a.create_by, a.create_time, a.update_by, a.update_time, a.remark,b.name as company_name,c.name as category_name
         from ex_course a
         left join sys_company b on b.id=a.company_id
         left join sys_category c on c.id=a.category_id
@@ -68,10 +69,24 @@
     </select>
 
     <select id="checkNameUnique" resultType="com.gkhy.exam.system.domain.ExCourse">
-        select id,name from ex_course where name=#{name} and company_id=#{companyId} and del_flag=0 limit 1
+        select id,name from ex_course where name=#{name} and del_flag=0
+        <if test="companyId!=null">
+            and company_id=#{companyId}
+        </if>
+        limit 1
     </select>
 
     <select id="selectCourseState" resultType="java.lang.Integer">
         select state from ex_course where id=#{courseId}
     </select>
+
+    <select id="selectCountByCategoryId" resultType="java.lang.Integer">
+        select count(1) from ex_course where category_id=#{categoryId} and del_flag=0
+    </select>
+
+    <select id="getCoursePeriod" resultType="java.lang.Long">
+        select sum(b.resource_length) from ex_course_chapter_period a
+        inner join ex_resource b on a.resource_id=b.id
+        where a.course_id=#{courseId}
+    </select>
 </mapper>
diff --git a/exam-system/src/main/resources/mapper/system/ExCoursePhaseMapper.xml b/exam-system/src/main/resources/mapper/system/ExCoursePhaseMapper.xml
index e843609..fc7cc68 100644
--- a/exam-system/src/main/resources/mapper/system/ExCoursePhaseMapper.xml
+++ b/exam-system/src/main/resources/mapper/system/ExCoursePhaseMapper.xml
@@ -15,11 +15,16 @@
         <result property="updateBy"       column="update_by"       />
         <result property="updateTime"     column="update_time"     />
         <result property="remark"         column="remark"          />
-        <result property="coursePeriod"         column="course_period"          />
+        <result property="courseName"         column="course_name"          />
+        <result property="companyName"         column="company_name"          />
+        <result property="studentCount"         column="student_count"          />
+        <result property="finishCount"         column="finish_count"          />
+        <association property="coursePeriod" javaType="java.lang.Long"  select="getCoursePeriod" column="{courseId=course_id}"/>
+        <association property="finishCount" javaType="java.lang.Integer"  select="getFinishStudentCount" column="{courseId=course_id,phaseId=id}"/>
     </resultMap>
 
     <sql id="selectCoursePhaseVo">
-        select a.id, a.name, a.code, a.company_id, a.course_id,a.level,a.del_flag,a.version, a.create_by, a.create_time, a.update_by, a.update_time, a.remark,b.period as course_period
+        select a.id, a.name, a.code, a.company_id, a.course_id,a.level,a.del_flag,a.version, a.create_by, a.create_time, a.update_by, a.update_time, a.remark,b.name as course_name
         from ex_course_phase a
         left join ex_course b on b.id=a.course_id
     </sql>
@@ -29,7 +34,12 @@
     </update>
 
     <select id="selectCoursePhaseList" resultMap="ExCoursePhaseResult">
-        <include refid="selectCoursePhaseVo"/>
+        select a.id, a.name, a.code, a.company_id, a.course_id,a.level,a.del_flag,a.version, a.create_by, a.create_time, a.update_by, a.update_time, a.remark,
+               b.name as course_name,c.name as company_name,
+               (select count(1) from ex_phase_student where phase_id=a.id) as student_count
+        from ex_course_phase a
+        left join ex_course b on b.id=a.course_id
+        left join sys_company c on c.id=a.company_id
         <where>
             and a.del_flag=0
             <if test="name != null and name != ''">
@@ -43,6 +53,9 @@
             </if>
             <if test="courseId != null and courseId != ''">
                 AND a.course_id =#{courseId}
+            </if>
+            <if test="level != null">
+                AND a.level =#{level}
             </if>
         </where>
         order by a.create_time desc
@@ -61,4 +74,14 @@
         select count(1) from ex_course_phase where del_flag=0 and courde_id=#{courseId}
     </select>
 
+    <select id="getCoursePeriod" resultType="java.lang.Long">
+        select sum(b.resource_length) from ex_course_chapter_period a
+        inner join ex_resource b on a.resource_id=b.id
+        where a.course_id=#{courseId}
+    </select>
+
+    <select id="getFinishStudentCount" resultType="java.lang.Integer">
+        select count(1) from (select student_id,count(1) as study_count from ex_student_study  where phase_id=#{phaseId} group by student_id) as a
+        where a.study_count=(select count(1) as period_count from ex_course_chapter_period  where course_id=#{courseId})
+    </select>
 </mapper>
diff --git a/exam-system/src/main/resources/mapper/system/ExExamPaperMapper.xml b/exam-system/src/main/resources/mapper/system/ExExamPaperMapper.xml
index 0daa0aa..cdfd48b 100644
--- a/exam-system/src/main/resources/mapper/system/ExExamPaperMapper.xml
+++ b/exam-system/src/main/resources/mapper/system/ExExamPaperMapper.xml
@@ -9,7 +9,7 @@
         <result property="companyId"         column="company_id"          />
         <result property="categoryId"         column="category_id"          />
         <result property="limitTime"         column="limit_time"          />
-        <result property="limit"         column="limit"          />
+        <result property="limited"         column="limited"          />
         <result property="singleNum"         column="single_num"          />
         <result property="singleScore"         column="single_score"          />
         <result property="singleBankId"         column="single_bank_id"          />
@@ -22,28 +22,38 @@
         <result property="judgeScore"         column="judge_score"          />
         <result property="judgeBankId"         column="judge_bank_id"          />
         <result property="judgeMethod"         column="judge_method"          />
+        <result property="easyNum"         column="easy_num"          />
+        <result property="easyScore"         column="easy_score"          />
+        <result property="easyBankId"         column="easy_bank_id"          />
+        <result property="easyMethod"         column="easy_method"          />
         <result property="passScore"         column="pass_score"          />
         <result property="version"         column="version"          />
         <result property="delFlag"         column="del_flag"          />
         <result property="createBy"       column="create_by"       />
+        <result property="deadline"     column="deadline"     />
         <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"          />
-        <collection property="singleQuestions" ofType="com.gkhy.exam.system.domain.ExQuestion" select="getQuestionByPaperId" column="{paperId=id,questionType=1}"/>
-        <collection property="multiQuestions" ofType="com.gkhy.exam.system.domain.ExQuestion" select="getQuestionByPaperId" column="{paperId=id,questionType=2}"/>
-        <collection property="judgeQuestions" ofType="com.gkhy.exam.system.domain.ExQuestion" select="getQuestionByPaperId" column="{paperId=id,questionType=3}"/>
+        <result property="categoryName"         column="category_name"          />
+        <association property="paperStudentInfoVO" javaType="com.gkhy.exam.system.domain.vo.PaperStudentInfoVO"  select="getPaperStudentInfoByPaperId" column="{paperId=id}"/>
+    </resultMap>
+    <resultMap type="com.gkhy.exam.system.domain.ExExamPaper" id="ExamPaperResult2" extends="ExamPaperResult">
+        <collection property="questions" ofType="com.gkhy.exam.system.domain.ExQuestion" select="getQuestionByPaperId" column="{paperId=id}"/>
     </resultMap>
 
 
+
     <sql id="selectExamPaperVo">
-        select a.id, a.name, a.code, a.status, a.company_id,a.category_id,a.limit_time,a.limit,a.single_num,a.single_score,a.single_bank_id,
+        select a.id, a.name, a.code, a.status, a.company_id,a.category_id,a.deadline,a.limit_time,a.limited,a.single_num,a.single_score,a.single_bank_id,
                a.single_method,a.multi_num,a.multi_score,
                a.multi_bank_id,a.multi_method,a.judge_num,a.judge_score,a.judge_bank_id,a.judge_method,a.pass_score,
-               a.version, a.create_by, a.create_time, a.update_by, a.update_time, a.remark,b.name as company_name
+               a.easy_num,a.easy_score,a.easy_bank_id,a.easy_method,
+               a.version, a.create_by, a.create_time, a.update_by, a.update_time, a.remark,b.name as company_name,c.name as category_name
         from ex_exam_paper a
         left join sys_company b on b.id=a.company_id
+        left join sys_category c on c.id=a.category_id
     </sql>
 
     <update id="deletePaperById">
@@ -64,11 +74,14 @@
             <if test="companyId != null and companyId != ''">
                 AND a.company_id= #{companyId}
             </if>
+            <if test="categoryId != null and categoryId != ''">
+                AND a.category_id= #{categoryId}
+            </if>
         </where>
         order by a.id desc
     </select>
 
-    <select id="selectExamPaperById" resultMap="ExamPaperResult">
+    <select id="selectExamPaperById" resultMap="ExamPaperResult2">
         <include refid="selectExamPaperVo"/>
         where a.id=#{paperId}
     </select>
@@ -78,16 +91,28 @@
     </select>
 
     <select id="checkNameUnique" resultType="com.gkhy.exam.system.domain.ExExamPaper">
-        select id ,name from ex_exam_paper where name=#{name} limit 1
+        select id ,name from ex_exam_paper where name=#{name} and del_flag=0
+        <if test="companyId!=null">
+            and company_id=#{companyId}
+        </if>
+        limit 1
     </select>
 
     <select id="getQuestionByPaperId" resultType="com.gkhy.exam.system.domain.ExQuestion">
         select a.* from ex_question a
         inner join ex_paper_question b on a.id=b.question_id
-        where b.paper_id=#{paperId} and a.question_type=#{questionType}
-        order by a.id asc
+        where b.paper_id=#{paperId}
+        order by a.question_type asc,a.id asc
     </select>
 
+    <select id="getPaperStudentInfoByPaperId" resultType="com.gkhy.exam.system.domain.vo.PaperStudentInfoVO">
+        select count(1) as student_count,ifnull(sum(passed),0) pass_student_count,ROUND(ifnull(avg(score),0),2) as avg_score,
+               (select count(1) from ex_paper_student where paper_id=#{paperId} and state!=0) as finish_count
+        from ex_paper_student  where paper_id=#{paperId}
+    </select>
+
+
+
 
 
 
diff --git a/exam-system/src/main/resources/mapper/system/ExExamRecordMapper.xml b/exam-system/src/main/resources/mapper/system/ExExamRecordMapper.xml
index 5f2e6c0..f438e61 100644
--- a/exam-system/src/main/resources/mapper/system/ExExamRecordMapper.xml
+++ b/exam-system/src/main/resources/mapper/system/ExExamRecordMapper.xml
@@ -19,13 +19,23 @@
         <result property="updateTime"     column="update_time"     />
         <result property="remark"         column="remark"          />
         <result property="companyName"         column="company_name"          />
+        <association property="student" javaType="com.gkhy.exam.system.domain.ExStudent" resultMap="exStudentResult" />
+    </resultMap>
+
+    <resultMap id="exStudentResult" type="com.gkhy.exam.system.domain.ExStudent">
+        <result property="id"       column="student_id"       />
+        <result property="name"       column="student_name"       />
+        <result property="phone"       column="student_phone"       />
+        <result property="idNo"       column="student_idno"       />
     </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
+               a.company_id,a.passed, a.create_by, a.create_time, a.update_by, a.update_time, a.remark,b.name as company_name,
+               c.name as student_name,c.id_no as student_idno,c.phone as student_phone
         from ex_exam_record a
         left join sys_company b on b.id=a.company_id
+        left join ex_student c on c.id=a.student_id
     </sql>
 
     <select id="selectExamRecordList" resultMap="ExamRecordResult">
diff --git a/exam-system/src/main/resources/mapper/system/ExExerciseAnswerMapper.xml b/exam-system/src/main/resources/mapper/system/ExExerciseAnswerMapper.xml
index a646754..39afa9d 100644
--- a/exam-system/src/main/resources/mapper/system/ExExerciseAnswerMapper.xml
+++ b/exam-system/src/main/resources/mapper/system/ExExerciseAnswerMapper.xml
@@ -6,6 +6,6 @@
     </delete>
 
     <select id="getExerciseAnswer" resultType="com.gkhy.exam.system.domain.ExExerciseAnswer">
-        select * from ex_exercise_answer where bank_id=#{bankId} and qustion_id=#{questionId} and student_id=#{studentId} limit 1
+        select * from ex_exercise_answer where bank_id=#{bankId} and question_id=#{questionId} and student_id=#{studentId} limit 1
     </select>
 </mapper>
diff --git a/exam-system/src/main/resources/mapper/system/ExPaperQuestionMapper.xml b/exam-system/src/main/resources/mapper/system/ExPaperQuestionMapper.xml
index cb6fb59..7c081f1 100644
--- a/exam-system/src/main/resources/mapper/system/ExPaperQuestionMapper.xml
+++ b/exam-system/src/main/resources/mapper/system/ExPaperQuestionMapper.xml
@@ -13,11 +13,12 @@
     </delete>
 
     <delete id="deletePaperQuestion">
-        delete from ex_paper_question
+        delete a from ex_paper_question as a
+        inner join ex_question as b on b.id=a.question_id
         <where>
-            and paper_id=#{paperId}
+            and a.paper_id=#{paperId}
            <if test="questionType!=null">
-               and question_type=#{questionType}
+               and b.question_type=#{questionType}
            </if>
         </where>
     </delete>
diff --git a/exam-system/src/main/resources/mapper/system/ExPaperStudentMapper.xml b/exam-system/src/main/resources/mapper/system/ExPaperStudentMapper.xml
index 7e000bd..f2c2602 100644
--- a/exam-system/src/main/resources/mapper/system/ExPaperStudentMapper.xml
+++ b/exam-system/src/main/resources/mapper/system/ExPaperStudentMapper.xml
@@ -8,7 +8,7 @@
         <result property="score"     column="score"     />
         <result property="passed"     column="passed"     />
         <result property="useTime"     column="use_time"     />
-        <result property="completed"     column="completed"     />
+        <result property="state"     column="state"     />
         <result property="version"         column="version"          />
         <result property="createBy"       column="create_by"       />
         <result property="createTime"     column="create_time"     />
@@ -18,10 +18,8 @@
         <result property="createName"         column="create_name"          />
         <association property="student" javaType="com.gkhy.exam.system.domain.ExStudent" resultMap="exStudentResult" />
         <association property="examPaper" javaType="com.gkhy.exam.system.domain.ExExamPaper" resultMap="exExamPaperResult" />
-        <collection property="singleQuestions" ofType="com.gkhy.exam.system.domain.ExQuestion" select="getQuestionByPaperId" column="{paperId=paper_id,studentId=student_id,completed=completed,questionType=1}"/>
-        <collection property="multiQuestions" ofType="com.gkhy.exam.system.domain.ExQuestion" select="getQuestionByPaperId" column="{paperId=paper_id,studentId=student_id,completed=completed,questionType=2}"/>
-        <collection property="judgeQuestions" ofType="com.gkhy.exam.system.domain.ExQuestion" select="getQuestionByPaperId" column="{paperId=paper_id,studentId=student_id,completed=completed,questionType=3}"/>
-    </resultMap>
+        <collection property="questions" ofType="com.gkhy.exam.system.domain.ExQuestion" select="getQuestionByPaperId" column="{paperId=paper_id,studentId=student_id,state=state}"/>
+     </resultMap>
 
 
     <resultMap type="com.gkhy.exam.system.domain.ExPaperStudent" id="SimplePaperStudentResult">
@@ -31,7 +29,8 @@
         <result property="score"     column="score"     />
         <result property="passed"     column="passed"     />
         <result property="useTime"     column="use_time"     />
-        <result property="completed"     column="completed"     />
+        <result property="startTime"     column="start_time"     />
+        <result property="state"     column="state"     />
         <result property="version"         column="version"          />
         <result property="createBy"       column="create_by"       />
         <result property="createTime"     column="create_time"     />
@@ -39,12 +38,23 @@
         <result property="updateTime"     column="update_time"     />
         <result property="remark"         column="remark"          />
         <result property="createName"         column="create_name"          />
+        <result property="companyId"         column="company_id"          />
+        <result property="companyName"         column="company_name"          />
         <association property="student" javaType="com.gkhy.exam.system.domain.ExStudent" resultMap="exStudentResult" />
         <association property="examPaper" javaType="com.gkhy.exam.system.domain.ExExamPaper" resultMap="exExamPaperResult" />
     </resultMap>
 
     <resultMap type="com.gkhy.exam.system.domain.ExQuestion" id="ExQuestionResult">
         <result property="id"       column="id"       />
+        <result property="questionType"    column="question_type"    />
+        <result property="bankId"     column="bank_id"     />
+        <result property="status"         column="status"          />
+        <result property="companyId"         column="company_id"          />
+        <result property="status"         column="status"          />
+        <result property="answer"         column="answer"          />
+        <result property="title"         column="title"          />
+        <result property="privatize"         column="privatize"          />
+        <result property="content"         column="content"          />
         <association property="studentAnswer" javaType="com.gkhy.exam.system.domain.ExStudentAnswer" resultMap="studentAnswerResult" />
     </resultMap>
 
@@ -55,6 +65,7 @@
         <result property="questionId"       column="answer_question_id"       />
         <result property="answer"       column="answer_answer"       />
         <result property="passed"       column="answer_passed"       />
+        <result property="score"       column="answer_score"       />
     </resultMap>
 
     <resultMap id="exExamPaperResult" type="com.gkhy.exam.system.domain.ExExamPaper">
@@ -62,6 +73,17 @@
         <result property="code"       column="paper_code"       />
         <result property="name"       column="paper_name"       />
         <result property="categoryName"       column="category_name"       />
+        <result property="limited"       column="limited"       />
+        <result property="limitTime"       column="limit_time"       />
+        <result property="deadline"       column="deadline"       />
+        <result property="singleNum"       column="single_num"       />
+        <result property="multiNum"       column="multi_num"       />
+        <result property="judgeNum"       column="judge_num"       />
+        <result property="easyNum"       column="easy_num"       />
+        <result property="singleScore"       column="single_score"       />
+        <result property="multiScore"       column="multi_score"       />
+        <result property="judgeScore"       column="judge_score"       />
+        <result property="easyScore"       column="easy_score"       />
     </resultMap>
 
     <resultMap id="exStudentResult" type="com.gkhy.exam.system.domain.ExStudent">
@@ -71,11 +93,19 @@
     </resultMap>
 
     <insert id="batchInsert">
-        insert into ex_paper_student(paper_id,student_id) values
+        insert into ex_paper_student(paper_id,student_id,create_id) values
         <foreach collection="list" item="item" index="index" separator=",">
-            (#{item.paperId},#{item.studentId})
+            (#{item.paperId},#{item.studentId},#{item.createId})
         </foreach>
     </insert>
+
+    <update id="batchUpdateComplete">
+        update ex_paper_student set completed=#{completed}
+        where id in
+        <foreach collection="paperStudentIds" item="item" open="(" separator="," close=")">
+            #{item}
+        </foreach>
+    </update>
 
     <select id="countByPaperId" resultType="java.lang.Integer">
         select count(1) from ex_paper_student where paper_id=#{paperId}
@@ -86,7 +116,11 @@
     </select>
 
     <select id="selectPaperStudentList" resultMap="SimplePaperStudentResult">
-        select a.*,e.name as create_name,b.phone as student_phone,b.name as student_name,c.name as paper_name,c.id as paper_id,c.code as paper_code,d.name as category_name  from ex_paper_student a
+        select a.*,e.name as create_name,b.phone as student_phone,b.name as student_name,c.name as paper_name,c.code as paper_code,c.limited,c.limit_time,c.deadline,d.name as category_name
+        <if test="studentId!=null">
+        ,(select question_id from ex_student_answer where paper_id=a.paper_id and student_id=#{studentId} order by id desc limit 1) as question_id
+        </if>
+        from ex_paper_student a
         left join ex_student b on a.student_id=b.id
         left join ex_exam_paper c on c.id=a.paper_id
         left join sys_category d on d.id=c.category_id
@@ -105,12 +139,15 @@
             <if test="studentId!=null">
                 and a.student_id = #{studentId}
             </if>
+            <if test="state!=null">
+                and a.state = #{state}
+            </if>
         </where>
-        order by a.id desc
+        order by a.passed desc,a.id desc
     </select>
 
     <select id="selectPaperStudentById" resultMap="ExPaperStudentResult">
-        select a.*,b.id as student_id,b.phone as student_phone,b.name as student_name,c.name as paper_name from ex_paper_student a
+        select a.*,b.id as student_id,b.phone as student_phone,b.name as student_name,c.name as paper_name,c.single_num,c.multi_num,c.judge_num,c.easy_num,c.single_score,c.multi_score,c.judge_score,c.easy_score from ex_paper_student a
         left join ex_student b on a.student_id=b.id
         left join ex_exam_paper c on c.id=a.paper_id
         where a.id=#{paperStudentId}
@@ -130,19 +167,31 @@
         where a.paper_id=#{paperId} and a.student_id=#{studentId}
     </select>
 
-    <select id="getQuestionByPaperId" resultType="com.gkhy.exam.system.domain.ExQuestion">
+    <select id="getQuestionByPaperId" resultMap="ExQuestionResult">
         select a.id,a.question_type,a.bank_id,a.company_id,a.status,
-               <if test="completed!=null and completed=1">
-               a.answer,
+               <if test="state!=null and state!=0">
+               a.answer,c.passed as answer_passed,c.score as answer_score,
                </if>
                a.title,a.privatize,a.content,
-               c.id as answer_id,c.paper_id as answer_paper_id,c.student_id as answer_student_id,c.question_id as answer_question_id,c.answer as answer_answer,
-                <if test="completed!=null and completed=1">
-               c.passed as answer_passed
-                </if>
+               c.id as answer_id,c.paper_id as answer_paper_id,c.student_id as answer_student_id,c.question_id as answer_question_id,c.answer as answer_answer
+
         from ex_question a
         inner join ex_paper_question b on a.id=b.question_id
         left join ex_student_answer c on c.question_id=a.id and c.student_id=#{studentId} and c.paper_id=#{paperId}
-        where b.paper_id=#{paperId} and a.question_type=#{questionType}
+        where b.paper_id=#{paperId}
+        order by a.question_type asc,a.id desc
+    </select>
+
+    <select id="selectByStudentId" resultMap="SimplePaperStudentResult">
+        select a.*,b.name as paper_name,c.id as company_id,c.name as company_name from ex_paper_student a
+        left join ex_exam_paper b on b.id=a.paper_id
+        left join sys_company c on c.id=b.company_id
+    </select>
+
+    <select id="selectNoCompleteStudent" resultMap="SimplePaperStudentResult">
+        select a.*, b.name as paper_name,b.limited,b.limit_time,b.deadline,b.single_num,b.multi_num,b.judge_num,b.easy_num
+        from ex_paper_student a
+        inner join ex_exam_paper b on b.id=a.paper_id
+        where a.state=0 limit #{startIndex},#{pageSize}
     </select>
 </mapper>
diff --git a/exam-system/src/main/resources/mapper/system/ExPhaseStudentMapper.xml b/exam-system/src/main/resources/mapper/system/ExPhaseStudentMapper.xml
index 87be86d..00173b6 100644
--- a/exam-system/src/main/resources/mapper/system/ExPhaseStudentMapper.xml
+++ b/exam-system/src/main/resources/mapper/system/ExPhaseStudentMapper.xml
@@ -11,7 +11,6 @@
         <result property="studentPhone"     column="student_phone"     />
         <result property="phaseName"     column="phase_name"     />
         <result property="createName"     column="create_name"     />
-        <result property="period"     column="period"     />
         <association property="course" javaType="com.gkhy.exam.system.domain.ExCourse" resultMap="courseResult" />
         <collection property="totalProgress" ofType="java.math.BigDecimal" select="getTotalProgress" column="{phaseId=phase_id,studentId=student_id}"/>
         <collection property="startTime" ofType="java.time.LocalDateTime" select="getStartTime" column="{phaseId=phase_id,studentId=student_id}"/>
@@ -21,20 +20,21 @@
         <id     property="id"       column="course_id"        />
         <result property="name"     column="course_name"      />
         <result property="logo"     column="course_logo"      />
+        <association property="period" javaType="java.lang.Long"  select="getCoursePeriod" column="{courseId=course_id}"/>
     </resultMap>
 
     <insert id="batchInsert" parameterType="java.util.List">
-        insert into ex_phase_student(phase_id,student_id) values
+        insert into ex_phase_student(phase_id,student_id,create_id) values
         <foreach collection="list" item="item" index="index" separator=",">
-            (#{item.phaseId},#{item.studentId})
+            (#{item.phaseId},#{item.studentId},#{item.createId})
         </foreach>
     </insert>
 
     <select id="countByPhaseId" resultType="java.lang.Integer">
-        select count(1) from ex_phase_student where phase_id#{phaseId}
+        select count(1) from ex_phase_student where phase_id=#{phaseId}
     </select>
 
-    <select id="selectPhaseStudentById" resultMap="ExPhaseStudentResult">
+    <select id="selectPhaseStudentById" resultType="com.gkhy.exam.system.domain.ExPhaseStudent">
         select a.*,b.phone as student_phone,b.name as student_name from ex_phase_student a
         left join ex_student b on a.student_id=b.id
         where a.id=#{phaseStudentId}
@@ -49,7 +49,7 @@
     </select>
 
     <select id="selectPhaseStudentList" resultMap="ExPhaseStudentResult">
-        select a.*,b.phone as student_phone,b.name as student_name,c.name as phase_name,d.period,e.name as create_name,d.id as course_id,d.logo as course_logo,d.name as course_name from ex_phase_student a
+        select a.*,b.phone as student_phone,b.name as student_name,c.name as phase_name,e.name as create_name,d.id as course_id,d.logo as course_logo,d.name as course_name from ex_phase_student a
         left join ex_student b on a.student_id=b.id
         left join ex_course_phase c on c.id=a.phase_id
         left join ex_course d on d.id=c.course_id
@@ -77,4 +77,19 @@
     </select>
 
 
+    <select id="getCoursePeriod" resultType="java.lang.Long">
+        select sum(b.resource_length) from ex_course_chapter_period a
+        inner join ex_resource b on a.resource_id=b.id
+        where a.course_id=#{courseId}
+    </select>
+
+    <select id="selectPhaseStudentByStudentId" resultType="com.gkhy.exam.system.domain.ExPhaseStudent"
+            parameterType="java.lang.Long">
+        select a.*,b.name as phase_name,c.id as company_id,c.name as company_name from ex_phase_student a
+        left join ex_course_phase b on b.id=a.phase_id
+        left join sys_company c on c.id=b.company_id
+        where a.student_id=#{studentId}
+    </select>
+
+
 </mapper>
diff --git a/exam-system/src/main/resources/mapper/system/ExQuestionBankMapper.xml b/exam-system/src/main/resources/mapper/system/ExQuestionBankMapper.xml
index bac3350..87ff02d 100644
--- a/exam-system/src/main/resources/mapper/system/ExQuestionBankMapper.xml
+++ b/exam-system/src/main/resources/mapper/system/ExQuestionBankMapper.xml
@@ -15,14 +15,23 @@
         <result property="updateBy"       column="update_by"       />
         <result property="updateTime"     column="update_time"     />
         <result property="remark"         column="remark"          />
+        <result property="singleCount"         column="single_count"          />
+        <result property="multiCount"         column="multi_count"          />
+        <result property="judgeCount"         column="judge_count"          />
         <result property="totalCount"         column="total_count"          />
         <result property="exerciseCount"         column="exercise_count"          />
+        <result property="categoryName"         column="category_name"          />
+        <result property="questionId"         column="question_id"          />
     </resultMap>
 
     <sql id="selectQuestionBankVo">
-        select id, name, category_id, status, del_flag,company_id,privatize,version, create_by, create_time, update_by, update_time, remark,
-               (select count(1) from ex_question where bank_id=a.id) as total_count
-        from ex_question_bank
+        select a.id, a.name, a.category_id, a.status, a.del_flag,a.company_id,a.privatize,a.version,
+               a.create_by, a.create_time, a.update_by, a.update_time, a.remark,b.name as category_name,
+               (select count(1) from ex_question where bank_id=a.id and question_type=1) as single_count,
+               (select count(1) from ex_question where bank_id=a.id and question_type=2) as multi_count,
+               (select count(1) from ex_question where bank_id=a.id and question_type=3) as judge_count
+        from ex_question_bank a
+        left join sys_category b on b.id=a.category_id
     </sql>
 
     <update id="deleteByBankId">
@@ -40,43 +49,55 @@
     <select id="selectQuestionBankList" resultMap="ExQuestionBankResult">
         <include refid="selectQuestionBankVo"/>
         <where>
-            and del_flag=0
+            and a.del_flag=0
             <if test="name != null and name != ''">
-                AND name like concat('%', #{name}, '%')
+                AND a.name like concat('%', #{name}, '%')
             </if>
             <if test="categoryId != null ">
-                AND categoryId =#{categoryId}
+                AND a.category_id =#{categoryId}
             </if>
             <if test="status != null ">
-                AND status =#{status}
+                AND a.status =#{status}
             </if>
             <if test="companyId != null ">
-                AND (company_id =#{companyId} or privatize=1)
-            </if>
-        </where>
-        order by id desc
-    </select>
-
-    <select id="selectQuestionBankListForStudent" resultType="com.gkhy.exam.system.domain.ExQuestionBank">
-        select a.*,
-        (select count(1) from ex_question where bank_id=a.id) as total_count,
-        b.exe_count as exercise_count
-        from ex_question_bank a
-        left join (select bank_id,count(*) as exe_count from ex_exercise_answer where student_id=#{studentId} group by bank_id) b on b.bank_id=a.id
-        <where>
-            and (a.company_id=#{companyId} or a.privatize=1) and a.del_flag=0
-            <if test="name!=null and name!=''">
-                a.name like concat('%',#{name},'%')
+                AND (a.company_id =#{companyId} or a.privatize=1)
             </if>
         </where>
         order by a.id desc
     </select>
 
+    <select id="selectQuestionBankListForStudent" resultType="com.gkhy.exam.system.domain.ExQuestionBank">
+        select a.*,
+        (select count(1) from ex_question where bank_id=a.id ) as total_count,
+        (select count(1)  from ex_exercise_answer where bank_id=a.id and student_id=#{studentId}) as exercise_count,
+        (select question_id from ex_exercise_answer where bank_id=a.id and student_id=#{studentId} order by id desc limit 1) as question_id
+        from ex_question_bank a
+        where a.del_flag=0 and (a.company_id=#{companyId} or a.privatize=1)
+        order by a.id desc
+    </select>
+
     <select id="selectQuestionBankByIdForStudent" resultType="com.gkhy.exam.system.domain.ExQuestionBank">
         select a.*,
-               (select count(1) from ex_question where bank_id=a.id) as total_count,
+               (select count(1) from ex_question where bank_id=a.id and question_type=1) as single_count,
+               (select count(1) from ex_question where bank_id=a.id and question_type=2) as multi_count,
+               (select count(1) from ex_question where bank_id=a.id and question_type=3) as judge_count,
                (select count(1)  from ex_exercise_answer where bank_id=#{bankId} and student_id=#{studentId}) as exercise_count
         from ex_question_bank a
         where a.bank_id=#{bankId}
     </select>
+
+    <select id="selectCountByBankId" resultType="java.lang.Integer" parameterType="java.lang.Long">
+        select count(1) from ex_question_bank where del_flag=0 and id=#{bankId}
+    </select>
+
+    <select id="selectCountByCategoryId" resultType="java.lang.Integer">
+        select count(1) from ex_question_bank where category_id=#{categoryId} and del_flag=0
+    </select>
+
+    <select id="selectQuestionBankByIds" resultType="com.gkhy.exam.system.domain.ExQuestionBank">
+        select * from ex_question_bank where del_flag=0 and id in
+        <foreach collection="bankIds" item="bankId" index="index" separator="," open="(" close=")">
+            #{bankId}
+        </foreach>
+    </select>
 </mapper>
diff --git a/exam-system/src/main/resources/mapper/system/ExQuestionMapper.xml b/exam-system/src/main/resources/mapper/system/ExQuestionMapper.xml
index dc2acc3..86c2181 100644
--- a/exam-system/src/main/resources/mapper/system/ExQuestionMapper.xml
+++ b/exam-system/src/main/resources/mapper/system/ExQuestionMapper.xml
@@ -18,6 +18,7 @@
         <result property="updateBy"       column="update_by"       />
         <result property="updateTime"     column="update_time"     />
         <result property="remark"         column="remark"          />
+        <result property="bankName"         column="bank_name"          />
         <association property="exExerciseAnswer" javaType="com.gkhy.exam.system.domain.ExExerciseAnswer" resultMap="ExerciseAnswerResult" />
         <association property="studentAnswer" javaType="com.gkhy.exam.system.domain.ExStudentAnswer" resultMap="StudentAnswerResult" />
     </resultMap>
@@ -51,32 +52,33 @@
     </select>
 
     <select id="selectQuestionWithLimit" resultType="com.gkhy.exam.system.domain.ExQuestion">
-        select id,title from ex_question where bank_id=#{bankId} and question_type=#{questionType} and (company_id=#{companyId} or privatize=1) limit #{startIndex},{questionCount}
+        select id,title from ex_question where bank_id=#{bankId} and question_type=#{questionType} and (company_id=#{companyId} or privatize=1) limit #{startIndex},#{questionCount}
     </select>
 
     <select id="selectRandomQuestion" resultType="com.gkhy.exam.system.domain.ExQuestion">
         select id,title from ex_question where bank_id=#{bankId} and question_type=#{questionType} and (company_id=#{companyId} or privatize=1) order by RAND()
-        limit {questionCount}
+        limit #{questionCount}
     </select>
 
     <select id="selectQuestionList" resultType="com.gkhy.exam.system.domain.ExQuestion">
-        select id,question_type, bank_id, status, company_id,answer,title,privatize from ex_question
+        select a.id,a.question_type, a.bank_id, a.status, a.company_id,a.title,a.privatize,b.name as bank_name from ex_question a
+        left join ex_question_bank b on b.id=a.bank_id
         <where>
             <if test="title!=null and title!=''">
-            title like concat(#{title},"%")
+                and a.title like concat(#{title},"%")
             </if>
             <if test="bankId!=null">
-                bank_id=#{bankId}
+                and a.bank_id=#{bankId}
             </if>
             <if test="companyId!=null">
-                company_id=#{companyId}
+                and (a.company_id=#{companyId} or a.privatize=1)
             </if>
             <if test="questionType!=null">
-                question_type=#{questionType}
+                and a.question_type=#{questionType}
             </if>
-            <if test="privatize!=null">
-                privatize=#{privatize}
-            </if>
+<!--            <if test="privatize!=null">-->
+<!--                and privatize=#{privatize}-->
+<!--            </if>-->
         </where>
         order by id desc
     </select>
@@ -85,12 +87,7 @@
         select a.id,b.passed from ex_question a
         left join ex_exercise_answer b on b.question_id=a.id and b.student_id=#{studentId}
         where a.bank_id=#{bankId}
-        <if test="exerciseType=2">
-            order by a.question_type asc,a.id asc
-        </if>
-        <if test="exerciseType=1">
-            order by a.id asc
-        </if>
+        order by a.question_type asc,a.id asc
     </select>
 
     <select id="getExeriseQuestionById" resultMap="ExQuestionResult">
@@ -106,18 +103,25 @@
         <foreach collection="questionIds" item="questionId" open="(" separator="," close=")">
             #{questionId}
         </foreach>
+        ORDER BY FIELD(a.id, <foreach collection="questionIds" item="questionId" separator=",">#{questionId}</foreach>)
     </select>
 
     <select id="getPaperQuestionList" resultType="java.util.Map">
         select a.id
-             <if test="completed=1">
-             ,c.passed
+             <if test="viewType==1">
+                ,
+                 case when c.answer is null then 0
+                 else 1
+                 end as state
              </if>
+            <if test="viewType==2">
+                <if test="state!=0">
+                    ,c.passed
+                </if>
+            </if>
         from ex_question a
         inner join ex_paper_question b on b.question_id=a.id
-        <if test="completed=1">
         left join ex_student_answer c on c.question_id=a.id and c.student_id=#{studentId} and c.paper_id=#{paperId}
-        </if>
         where b.paper_id=#{paperId}
         order by a.question_type asc,a.id asc
     </select>
@@ -125,7 +129,7 @@
     <select id="getPaperQuestionById" resultMap="ExQuestionResult">
         select a.id,a.question_type,a.bank_id,a.company_id,a.title,a.content,a.privatize,
                b.id as student_answer_id, b.answer as student_answer,b.question_id,b.student_id
-               <if test="completed=1">
+               <if test="state!=0">
                    ,a.answer,b.passed as student_passed
                </if>
         from ex_question a
@@ -133,10 +137,10 @@
         where a.id=#{questionId}
     </select>
 
-    <select id="getPaperQuestionByIds" resultType="com.gkhy.exam.system.domain.ExQuestion">
+    <select id="getPaperQuestionByIds" resultMap="ExQuestionResult">
         select a.id,a.question_type,a.bank_id,a.company_id,a.title,a.content,a.privatize,
         b.id as student_answer_id, b.answer as student_answer,b.question_id,b.student_id
-        <if test="completed=1">
+        <if test="state!=0">
             ,a.answer,b.passed as student_passed
         </if>
         from ex_question a
@@ -145,14 +149,28 @@
         <foreach collection="questionIds" item="questionId" open="(" separator="," close=")">
             #{questionId}
         </foreach>
+        ORDER BY FIELD(a.id, <foreach collection="questionIds" item="questionId" separator=",">#{questionId}</foreach>)
     </select>
 
     <select id="getExerciseErrorQuestionList" resultType="java.lang.Long">
         select a.id from ex_question a
         inner join ex_exercise_answer b on b.question_id=a.id
-        where a.bank_id=#{bankId} and b.student_id=#{studentId}
+        where a.bank_id=#{bankId} and b.student_id=#{studentId} and b.passed=0
         order by a.question_type asc,a.id asc
     </select>
 
+    <select id="selectByQuestionId" resultType="com.gkhy.exam.system.domain.ExQuestion">
+        select a.*,b.name as bank_name from ex_question a
+        left join ex_question_bank b on b.id=a.bank_id
+        where a.id=#{questionId}
+    </select>
+
+    <select id="selectQuestionByPaperId" resultType="com.gkhy.exam.system.domain.ExQuestion"
+            parameterType="java.lang.Long">
+        select a.* from ex_question a
+        inner join ex_paper_question b on b.question_id=a.id
+        where b.paper_id=#{paperId}
+    </select>
+
 
 </mapper>
diff --git a/exam-system/src/main/resources/mapper/system/ExResourceMapper.xml b/exam-system/src/main/resources/mapper/system/ExResourceMapper.xml
index 40b2dfd..d356076 100644
--- a/exam-system/src/main/resources/mapper/system/ExResourceMapper.xml
+++ b/exam-system/src/main/resources/mapper/system/ExResourceMapper.xml
@@ -65,5 +65,10 @@
         where b.id=#{periodId}
     </select>
 
+    <select id="checkResourceAssign" resultType="java.lang.Integer" parameterType="java.lang.Long">
+        select count(1) from ex_course_chapter_period a
+        where a.resource_id=#{resourceId}
+    </select>
+
 
 </mapper>
diff --git a/exam-system/src/main/resources/mapper/system/ExStudentAnswerMapper.xml b/exam-system/src/main/resources/mapper/system/ExStudentAnswerMapper.xml
index 48ba21e..c283c0a 100644
--- a/exam-system/src/main/resources/mapper/system/ExStudentAnswerMapper.xml
+++ b/exam-system/src/main/resources/mapper/system/ExStudentAnswerMapper.xml
@@ -9,7 +9,7 @@
     <select id="selectPassCount" resultType="java.lang.Integer">
         select count(1) from ex_student_answer a
         inner join ex_question b on b.id=a.question_id
-        where a.paper_id=#{paperId} and a.student_id=#{studentId} and b.questionType=#{questionType} and a.passed=1
+        where a.paper_id=#{paperId} and a.student_id=#{studentId} and b.question_type=#{questionType} and a.passed=1
     </select>
 
     <select id="getStudentAnswer" resultType="com.gkhy.exam.system.domain.ExStudentAnswer">
diff --git a/exam-system/src/main/resources/mapper/system/ExStudentMapper.xml b/exam-system/src/main/resources/mapper/system/ExStudentMapper.xml
index ec3470c..ff0e4f1 100644
--- a/exam-system/src/main/resources/mapper/system/ExStudentMapper.xml
+++ b/exam-system/src/main/resources/mapper/system/ExStudentMapper.xml
@@ -27,18 +27,25 @@
         <result property="remark"         column="remark"          />
 
         <association property="company" javaType="com.gkhy.exam.system.domain.SysCompany" resultMap="companyResult" />
+        <association property="createUser" javaType="com.gkhy.exam.common.domain.entity.SysUser" resultMap="userResult" />
     </resultMap>
     <resultMap id="companyResult" type="com.gkhy.exam.system.domain.SysCompany">
         <id     property="id"       column="company_id"        />
         <result property="name"     column="company_name"      />
     </resultMap>
 
+    <resultMap id="userResult" type="com.gkhy.exam.common.domain.entity.SysUser">
+        <id     property="id"       column="create_id"        />
+        <result property="name"     column="create_name"      />
+    </resultMap>
+
     <sql id="selectStudentVo">
-        select s.id, s.name, s.company_id, s.empno, s.phone,s.password,s.status,s.sex,s.id_no,s.post,s.duty,
+        select s.id, s.name, s.company_id, s.empno, s.phone,s.status,s.sex,s.id_no,s.post,s.duty,
                s.create_id,s.del_flag,s.version, s.create_by, s.create_time, s.update_by, s.update_time, s.remark,
-                c.id as company_id,c.name as company_name
+                c.id as company_id,c.name as company_name,d.name as create_name
         from ex_student s
         left join sys_company c on c.id=s.company_id
+        left join sys_user d on d.id=s.create_id
     </sql>
 
     <update id="deleteByStudentId">
@@ -62,6 +69,15 @@
             <if test="idNo != null and idNo != ''">
                 AND s.id_no like concat('%', #{idNo}, '%')
             </if>
+            <if test="createId != null">
+                AND s.create_id =#{createId}
+            </if>
+            <if test="params.createIds != null and params.createIds != ''">
+                AND s.create_id in
+                <foreach collection="params.createIds" item="createId" open="(" separator="," close=")">
+                    #{createId}
+                </foreach>
+            </if>
         </where>
         order by s.id desc
     </select>
@@ -79,7 +95,7 @@
     </select>
 
     <select id="selectStudentByPhone" resultType="com.gkhy.exam.system.domain.ExStudent">
-        select * from ex_student where phone=#{phone}  limit 1
+        select * from ex_student where phone=#{phone} and del_flag=0  limit 1
     </select>
 
 </mapper>
diff --git a/exam-system/src/main/resources/mapper/system/ExStudentStudyMapper.xml b/exam-system/src/main/resources/mapper/system/ExStudentStudyMapper.xml
index f9c8ae5..e4a0b79 100644
--- a/exam-system/src/main/resources/mapper/system/ExStudentStudyMapper.xml
+++ b/exam-system/src/main/resources/mapper/system/ExStudentStudyMapper.xml
@@ -11,7 +11,6 @@
         <result property="currentDuration"         column="current_duration"          />
         <result property="currentPage"         column="current_page"          />
         <result property="progress"         column="progress"          />
-        <result property="resourceType"         column="resource_type"          />
         <result property="createBy"       column="create_by"       />
         <result property="createTime"     column="create_time"     />
         <result property="updateBy"       column="update_by"       />
@@ -24,7 +23,7 @@
     </resultMap>
 
     <sql id="selectStudentStudyVo">
-        select a.id, a.phase_id, a.course_id, a.chapter_id, a.period_id,a.student_id,a.current_duration,a.current_page,a.progress,a.resource_type,
+        select a.id, a.phase_id, a.course_id, a.chapter_id, a.period_id,a.student_id,a.current_duration,a.current_page,a.progress,
                a.version, a.create_by, a.create_time, a.update_by, a.update_time, a.remark,b.name as course_name,d.name as chapter_mame,c.name as period_name
         from ex_student_study a
         left join ex_course b on b.id=a.course_id
@@ -45,6 +44,6 @@
     </select>
 
     <select id="selectStudyByObject" resultType="com.gkhy.exam.system.domain.ExStudentStudy">
-        select * from ex_student_study where paper_id=#{paperId} and  period_id=#{periodId} and student_id=#{studentId}
+        select * from ex_student_study where phase_id=#{phaseId} and  period_id=#{periodId} and student_id=#{studentId} limit 1
     </select>
 </mapper>
diff --git a/exam-system/src/main/resources/mapper/system/SysCarouselMapper.xml b/exam-system/src/main/resources/mapper/system/SysCarouselMapper.xml
index 6fef797..e837ded 100644
--- a/exam-system/src/main/resources/mapper/system/SysCarouselMapper.xml
+++ b/exam-system/src/main/resources/mapper/system/SysCarouselMapper.xml
@@ -32,7 +32,7 @@
                 AND status =#{status}
             </if>
         </where>
-        order by create_time desc
+        order by id desc
     </select>
 
     <select id="selectCarouselById" resultMap="SysCarouselResult">
diff --git a/exam-system/src/main/resources/mapper/system/SysCategoryMapper.xml b/exam-system/src/main/resources/mapper/system/SysCategoryMapper.xml
index 6efd070..37d216c 100644
--- a/exam-system/src/main/resources/mapper/system/SysCategoryMapper.xml
+++ b/exam-system/src/main/resources/mapper/system/SysCategoryMapper.xml
@@ -7,6 +7,7 @@
         <result property="parentId"     column="parent_id"     />
         <result property="status"         column="status"          />
         <result property="sort"         column="sort"          />
+        <result property="delFlag"         column="del_flag"          />
         <result property="version"         column="version"          />
         <result property="createBy"       column="create_by"       />
         <result property="createTime"     column="create_time"     />
@@ -16,13 +17,18 @@
     </resultMap>
 
     <sql id="selectCategoryVo">
-        select id, name, parent_id, category_type, status,sort,version, create_by, create_time, update_by, update_time, remark
+        select id, name, parent_id, category_type, status,sort,del_flag,version, create_by, create_time, update_by, update_time, remark
         from sys_category
     </sql>
+
+    <update id="deleteByCategoryId" parameterType="java.lang.Long">
+        update sys_category set del_flag=1 where id=#{categoryId}
+    </update>
 
     <select id="selectCategoryList" resultMap="SysCategoryResult">
         <include refid="selectCategoryVo"/>
         <where>
+            and del_flag=0
             <if test="name != null and name != ''">
                 AND name like concat('%', #{name}, '%')
             </if>
@@ -34,15 +40,7 @@
     </select>
 
     <select id="checkNameUnique" resultType="com.gkhy.exam.system.domain.SysCategory">
-        select id,name,parent_id from sys_category where name=#{name} and parent_id=#{parentId} limit 1
-    </select>
-
-    <select id="selectCountOfCoure" resultType="java.lang.Integer">
-        select count(1) from ex_course where category_id=#{categoryId} and del_flag=0
-    </select>
-
-    <select id="selectCountOfBank" resultType="java.lang.Integer">
-        select count(1) from ex_question_bank where category_id=#{categoryId} and del_flag=0
+        select id,name,parent_id from sys_category where name=#{name} and parent_id=#{parentId} and del_flag=0 limit 1
     </select>
 
 </mapper>
diff --git a/exam-system/src/main/resources/mapper/system/SysCompanyMapper.xml b/exam-system/src/main/resources/mapper/system/SysCompanyMapper.xml
index bf14ee4..5560830 100644
--- a/exam-system/src/main/resources/mapper/system/SysCompanyMapper.xml
+++ b/exam-system/src/main/resources/mapper/system/SysCompanyMapper.xml
@@ -9,7 +9,6 @@
         <result property="phone"         column="phone"          />
         <result property="delFlag"         column="del_flag"          />
         <result property="remainPeriod"         column="remain_period"          />
-        <result property="spendPeriod"         column="spend_period"          />
         <result property="totalPeriod"         column="total_period"          />
         <result property="version"         column="version"          />
         <result property="createBy"       column="create_by"       />
@@ -20,7 +19,7 @@
     </resultMap>
 
     <sql id="selectCompanyVo">
-        select id, name, credit_code, major, phone,remain_period,spend_period,total_period,version, create_by, create_time, update_by, update_time, remark
+        select id, name, credit_code, major, phone,remain_period,total_period,version, create_by, create_time, update_by, update_time, remark
         from sys_company
     </sql>
 
diff --git a/exam-system/src/main/resources/mapper/system/SysUserMapper.xml b/exam-system/src/main/resources/mapper/system/SysUserMapper.xml
index 641ad44..7d6e693 100644
--- a/exam-system/src/main/resources/mapper/system/SysUserMapper.xml
+++ b/exam-system/src/main/resources/mapper/system/SysUserMapper.xml
@@ -24,6 +24,7 @@
         <result property="remark"        column="remark"          />
         <result property="version"        column="version"          />
         <result property="companyName"        column="company_name"          />
+        <result property="remainPeriod"        column="remain_period"          />
         <result property="parentName"        column="parent_name"          />
     </resultMap>
 
@@ -35,12 +36,12 @@
 
 
     <select id="getUserByUsername" resultMap="SysUserResult">
-        select id,username,name,password,user_type,company_id,status,del_flag from sys_user
-        where username=#{username} limit 1
+        select id,username,name,password,user_type,company_id,status,del_flag,parent_id from sys_user
+        where username=#{username} and del_flag=0 limit 1
     </select>
 
     <select id="userList"  resultMap="SysUserResult">
-        select u.id,u.username,u.name,u.user_type,u.phone,u.parent_id,u.company_id,u.sex,u.status,u.del_flag,
+        select u.id,u.username,u.name,u.user_type,u.phone,u.parent_id,u.company_id,u.sex,u.status,u.del_flag,u.version,
                u.login_ip,u.login_date,u.create_by,u.create_time,u.remark,c.name as company_name,su.name as parent_name
         from sys_user u
         left join sys_company c on c.id=u.company_id
@@ -49,6 +50,9 @@
             and u.del_flag = 0
             <if test="username != null and username != ''">
                 AND u.username like concat('%', #{username}, '%')
+            </if>
+            <if test="name != null and name != ''">
+                AND u.name like concat('%', #{name}, '%')
             </if>
             <if test="status != null and status != ''">
                 AND u.status = #{status}
@@ -68,10 +72,17 @@
             <if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
                 AND date_format(u.create_time,'%y%m%d') &lt;= date_format(#{params.endTime},'%y%m%d')
             </if>
-            <if test="params.userType != null">
-                AND u.user_type >#{params.userType}
+            <if test="params.userType != null and (params.userType==4 or params.userType==1)">
+                AND u.user_type in (2,3)
+            </if>
+            <if test="params.userType != null and params.userType==2">
+                AND u.user_type in (3)
+            </if>
+            <if test="params.userType != null and params.userType==0">
+                AND u.user_type in (1,2,3,4)
             </if>
         </where>
+        order by u.id desc
     </select>
 
 
@@ -82,7 +93,7 @@
     </select>
 
     <select id="getUserById" resultMap="SysUserResult">
-        select u.id,u.username,u.user_type,u.name,u.phone,u.parent_id,u.company_id,u.status,u.sex,u.del_flag,c.name as company_name,su.name as parent_name
+        select u.id,u.username,u.user_type,u.name,u.phone,u.parent_id,u.company_id,u.status,u.sex,u.del_flag,u.version,c.name as company_name,c.remain_period,su.name as parent_name
         from sys_user u
        left join sys_company c on c.id=u.company_id
        left join sys_user su on su.id=u.parent_id and u.parent_id!=0
@@ -97,4 +108,8 @@
         select id,phone from sys_user where phone=#{phone} and del_flag=0 limit 1
     </select>
 
+    <select id="selectWorkshopUserIds" resultType="java.lang.Long" parameterType="java.lang.Long">
+        select id from sys_user where parent_id=#{departUserId} and del_flag=0 and user_type=3
+    </select>
+
 </mapper>
diff --git a/pom.xml b/pom.xml
index 6df8bcf..723427f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -35,7 +35,7 @@
         <mybatis-plus.version>3.5.1</mybatis-plus.version>
         <mysql-connector.version>8.0.29</mysql-connector.version>
         <jwt.version>0.9.1</jwt.version>
-        <fastjson.version>2.0.48</fastjson.version>
+        <fastjson.version>2.0.52</fastjson.version>
         <caffeine.version>2.9.3</caffeine.version>
         <minio.version>8.4.5</minio.version>
         <kaptcha.version>2.3.3</kaptcha.version>
@@ -44,6 +44,8 @@
         <poi.version>5.2.3</poi.version>
         <pdfbox.version>2.0.27</pdfbox.version>
         <jaudiotagger.version>2.0.1</jaudiotagger.version>
+        <easyexcel.version>4.0.2</easyexcel.version>
+
     </properties>
     <dependencyManagement>
         <dependencies>
@@ -130,6 +132,16 @@
                 <version>${fastjson.version}</version>
             </dependency>
             <dependency>
+                <groupId>com.alibaba.fastjson2</groupId>
+                <artifactId>fastjson2-extension</artifactId>
+                <version>${fastjson.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.alibaba.fastjson2</groupId>
+                <artifactId>fastjson2-extension-spring5</artifactId>
+                <version>${fastjson.version}</version>
+            </dependency>
+            <dependency>
                 <groupId>com.github.ben-manes.caffeine</groupId>
                 <artifactId>caffeine</artifactId>
                 <version>${caffeine.version}</version>
@@ -187,6 +199,11 @@
                 <version>${jaudiotagger.version}</version>
             </dependency>
 
+            <dependency>
+                <groupId>com.alibaba</groupId>
+                <artifactId>easyexcel</artifactId>
+                <version>${easyexcel.version}</version>
+            </dependency>
         </dependencies>
     </dependencyManagement>
 

--
Gitblit v1.9.2