Merge develop into main #2 #14

Merged
pswqm3ot6 merged 10 commits from develop into main 3 months ago

@ -10,4 +10,9 @@
</profile> </profile>
</annotationProcessing> </annotationProcessing>
</component> </component>
<component name="JavacSettings">
<option name="ADDITIONAL_OPTIONS_OVERRIDE">
<module name="exam" options="-parameters" />
</option>
</component>
</project> </project>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/backend/src/main/java" charset="UTF-8" />
</component>
</project>

@ -2,5 +2,6 @@
<profile version="1.0"> <profile version="1.0">
<option name="myName" value="Project Default" /> <option name="myName" value="Project Default" />
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" /> <inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="MapOrSetKeyShouldOverrideHashCodeEquals" enabled="true" level="WARNING" enabled_by_default="true" />
</profile> </profile>
</component> </component>

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Central Repository" />
<option name="url" value="https://repo.maven.apache.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
</component>
</project>

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.svg" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>

@ -2,5 +2,6 @@
<project version="4"> <project version="4">
<component name="VcsDirectoryMappings"> <component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" /> <mapping directory="$PROJECT_DIR$/.." vcs="Git" />
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component> </component>
</project> </project>

@ -1,15 +1,17 @@
// 指定当前类所在的包路径这是Java中组织类的一种方式有助于类的管理和访问控制。
package lsgwr.exam; package lsgwr.exam;
// 导入Spring Boot的启动类和应用配置自动装配的注解类。
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
// @SpringBootApplication是一个方便的注解它包括了@Configuration@EnableAutoConfiguration和@ComponentScan注解。
/** // 它告诉Spring Boot基于当前类所在包及其子包下的组件来启动自动配置和组件扫描。
* Spring BootSpring Boot
*/
@SpringBootApplication @SpringBootApplication
public class ExamApplication { public class ExamApplication {
// main方法是Java应用程序的入口点。当运行这个类时JVM会调用这个方法。
public static void main(String[] args) { public static void main(String[] args)
{
// SpringApplication.run方法启动Spring应用传入ExamApplication.class当前启动类和main方法的参数args。
// 这个方法会执行一系列的操作包括启动Spring容器加载应用上下文自动配置等。
SpringApplication.run(ExamApplication.class, args); SpringApplication.run(ExamApplication.class, args);
} }
} }

@ -12,12 +12,21 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
*
*/
@Configuration @Configuration
public class IntercepterConfig implements WebMvcConfigurer { public class IntercepterConfig implements WebMvcConfigurer {
/**
* LoginInterceptor
*/
@Autowired @Autowired
private LoginInterceptor loginInterceptor; private LoginInterceptor loginInterceptor;
/**
*
*/
@Override @Override
public void addInterceptors(InterceptorRegistry registry) { public void addInterceptors(InterceptorRegistry registry) {
// 拦截user下的api // 拦截user下的api

@ -7,12 +7,22 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
/**
* Servlet
*/
@Configuration @Configuration
public class ServletConfig { public class ServletConfig {
/**
* WebServerFactoryCustomizer beanWeb
* @return WebServerFactoryCustomizer<ConfigurableWebServerFactory>
*/
@Bean @Bean
public WebServerFactoryCustomizer<ConfigurableWebServerFactory> webServerFactoryCustomizer() { public WebServerFactoryCustomizer<ConfigurableWebServerFactory> webServerFactoryCustomizer() {
// 返回一个lambda表达式用于自定义Web服务器的工厂
return factory -> { return factory -> {
// 创建一个ErrorPage对象用于处理404错误
ErrorPage error404Page = new ErrorPage(HttpStatus.NOT_FOUND, "/"); ErrorPage error404Page = new ErrorPage(HttpStatus.NOT_FOUND, "/");
// 将ErrorPage对象添加到Web服务器的工厂中
factory.addErrorPages(error404Page); factory.addErrorPages(error404Page);
}; };
} }

@ -23,12 +23,18 @@ import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
/**
* Swagger2
*/
@Configuration @Configuration
@EnableSwagger2 @EnableSwagger2
public class Swagger2Config { public class Swagger2Config {
/**
* Docket bean
* @return Docket
*/
@Bean @Bean
public Docket api() { public Docket api() {
ParameterBuilder ticketPar = new ParameterBuilder(); ParameterBuilder ticketPar = new ParameterBuilder();
List<Parameter> pars = new ArrayList<>(); List<Parameter> pars = new ArrayList<>();
ticketPar.name("Access-Token").description("Rest接口权限认证token,无需鉴权可为空") ticketPar.name("Access-Token").description("Rest接口权限认证token,无需鉴权可为空")
@ -48,6 +54,10 @@ public class Swagger2Config {
.globalOperationParameters(pars); .globalOperationParameters(pars);
} }
/**
* ApiInfo
* @return ApiInfo
*/
private ApiInfo apiInfo() { private ApiInfo apiInfo() {
return new ApiInfoBuilder() return new ApiInfoBuilder()
.title("online exam by springboot") .title("online exam by springboot")

@ -31,32 +31,39 @@ public class ExamController {
*/ */
@GetMapping("/question/all") @GetMapping("/question/all")
@ApiOperation("获取所有问题的列表") @ApiOperation("获取所有问题的列表")
ResultVO<List<QuestionVo>> getQuestionAll() { // 获取全部问题列表。
ResultVO<List<QuestionVo>> getQuestionAll() {
// 定义返回值。
ResultVO<List<QuestionVo>> resultVO; ResultVO<List<QuestionVo>> resultVO;
try { try {
// 调用examService获取全部问题列表。
List<QuestionVo> questionAll = examService.getQuestionAll(); List<QuestionVo> questionAll = examService.getQuestionAll();
// 返回成功结果。
resultVO = new ResultVO<>(0, "获取全部问题列表成功", questionAll); resultVO = new ResultVO<>(0, "获取全部问题列表成功", questionAll);
} catch (Exception e) { } catch (Exception e) {
// 打印异常信息。
e.printStackTrace(); e.printStackTrace();
// 返回失败结果。
resultVO = new ResultVO<>(-1, "获取全部问题列表失败", null); resultVO = new ResultVO<>(-1, "获取全部问题列表失败", null);
} }
// 返回结果。
return resultVO; return resultVO;
} }
/**
* @Description: QuestionVo使examService.updateQuestion()
* @param questionVo QuestionVo
*/
@PostMapping("/question/update") @PostMapping("/question/update")
@ApiOperation("更新问题") @ApiOperation("更新问题")
ResultVO<QuestionVo> questionUpdate(@RequestBody QuestionVo questionVo) { ResultVO<QuestionVo> questionUpdate(@RequestBody QuestionVo questionVo) {
// 完成问题的更新 // 完成问题的更新。
System.out.println(questionVo); System.out.println(questionVo);
try { try {
// 调用examService的updateQuestion方法更新问题。
QuestionVo questionVoResult = examService.updateQuestion(questionVo); QuestionVo questionVoResult = examService.updateQuestion(questionVo);
// 返回更新成功的结果。
return new ResultVO<>(0, "更新问题成功", questionVoResult); return new ResultVO<>(0, "更新问题成功", questionVoResult);
} catch (Exception e) { } catch (Exception e) {
// 打印异常信息。
e.printStackTrace(); e.printStackTrace();
// 返回更新失败的结果。
return new ResultVO<>(-1, "更新问题失败", null); return new ResultVO<>(-1, "更新问题失败", null);
} }
} }
@ -71,18 +78,23 @@ public class ExamController {
@PostMapping("/question/create") @PostMapping("/question/create")
@ApiOperation("创建问题") @ApiOperation("创建问题")
ResultVO<String> questionCreate(@RequestBody QuestionCreateSimplifyVo questionCreateSimplifyVo, HttpServletRequest request) { ResultVO<String> questionCreate(@RequestBody QuestionCreateSimplifyVo questionCreateSimplifyVo, HttpServletRequest request) {
// 创建一个QuestionCreateVo对象。
QuestionCreateVo questionCreateVo = new QuestionCreateVo(); QuestionCreateVo questionCreateVo = new QuestionCreateVo();
// 把能拷贝过来的属性都拷贝过来 // 把能拷贝过来的属性都拷贝过来
BeanUtils.copyProperties(questionCreateSimplifyVo, questionCreateVo); BeanUtils.copyProperties(questionCreateSimplifyVo, questionCreateVo);
// 设置创建者信息 // 设置创建者信息
String userId = (String) request.getAttribute("user_id"); String userId = (String) request.getAttribute("user_id");
questionCreateVo.setQuestionCreatorId(userId); questionCreateVo.setQuestionCreatorId(userId);
System.out.println(questionCreateVo); System.out.println(questionCreateVo);
try { try {
// 调用examService的questionCreate方法创建问题。
examService.questionCreate(questionCreateVo); examService.questionCreate(questionCreateVo);
// 返回问题创建成功的ResultVO。
return new ResultVO<>(0, "问题创建成功", null); return new ResultVO<>(0, "问题创建成功", null);
} catch (Exception e) { } catch (Exception e) {
// 打印异常信息。
e.printStackTrace(); e.printStackTrace();
// 返回创建问题失败的ResultVO。
return new ResultVO<>(-1, "创建问题失败", null); return new ResultVO<>(-1, "创建问题失败", null);
} }
} }
@ -93,11 +105,16 @@ public class ExamController {
*/ */
@GetMapping("/question/selection") @GetMapping("/question/selection")
@ApiOperation("获取问题分类的相关选项") @ApiOperation("获取问题分类的相关选项")
ResultVO<QuestionSelectionVo> getSelections() { // 获取问题分类选项。
ResultVO<QuestionSelectionVo> getSelections() {
// 调用examService的getSelections方法获取问题分类选项。
QuestionSelectionVo questionSelectionVo = examService.getSelections(); QuestionSelectionVo questionSelectionVo = examService.getSelections();
// 如果获取成功。
if (questionSelectionVo != null) { if (questionSelectionVo != null) {
// 返回成功的结果。
return new ResultVO<>(0, "获取问题分类选项成功", questionSelectionVo); return new ResultVO<>(0, "获取问题分类选项成功", questionSelectionVo);
} else { } else {
// 否则返回失败的结果。
return new ResultVO<>(-1, "获取问题分类选项失败", null); return new ResultVO<>(-1, "获取问题分类选项失败", null);
} }
} }
@ -110,16 +127,21 @@ public class ExamController {
@GetMapping("/question/detail/{id}") @GetMapping("/question/detail/{id}")
@ApiOperation("根据问题的id获取问题的详细信息") @ApiOperation("根据问题的id获取问题的详细信息")
ResultVO<QuestionDetailVo> getQuestionDetail(@PathVariable String id) { ResultVO<QuestionDetailVo> getQuestionDetail(@PathVariable String id) {
// 根据问题id获取问题的详细信息 // 根据问题id获取问题的详细信息
System.out.println(id); System.out.println(id);
ResultVO<QuestionDetailVo> resultVO; ResultVO<QuestionDetailVo> resultVO;
try { try {
// 调用examService的getQuestionDetail方法根据问题id获取问题的详细信息。
QuestionDetailVo questionDetailVo = examService.getQuestionDetail(id); QuestionDetailVo questionDetailVo = examService.getQuestionDetail(id);
// 如果获取成功则返回ResultVO对象状态码为0提示信息为"获取问题详情成功"数据为questionDetailVo。
resultVO = new ResultVO<>(0, "获取问题详情成功", questionDetailVo); resultVO = new ResultVO<>(0, "获取问题详情成功", questionDetailVo);
} catch (Exception e) { } catch (Exception e) {
// 如果获取失败则打印异常信息并返回ResultVO对象状态码为-1提示信息为"获取问题详情失败"数据为null。
e.printStackTrace(); e.printStackTrace();
// 创建一个表示获取失败的ResultVO对象状态码设置为 -1表示获取操作失败消息设置为"获取问题详情失败"数据部分设置为null
resultVO = new ResultVO<>(-1, "获取问题详情失败", null); resultVO = new ResultVO<>(-1, "获取问题详情失败", null);
} }
// 返回ResultVO对象。
return resultVO; return resultVO;
} }
@ -130,13 +152,17 @@ public class ExamController {
@GetMapping("/all") @GetMapping("/all")
@ApiOperation("获取全部考试的列表") @ApiOperation("获取全部考试的列表")
ResultVO<List<ExamVo>> getExamAll() { ResultVO<List<ExamVo>> getExamAll() {
// 需要拼接前端需要的考试列表对象 // 需要拼接前端需要的考试列表对象
ResultVO<List<ExamVo>> resultVO; ResultVO<List<ExamVo>> resultVO;
try { try {
// 调用examService的getExamAll方法获取全部考试的列表。
List<ExamVo> examVos = examService.getExamAll(); List<ExamVo> examVos = examService.getExamAll();
// 将获取到的考试列表封装到ResultVO对象中并返回。
resultVO = new ResultVO<>(0, "获取全部考试的列表成功", examVos); resultVO = new ResultVO<>(0, "获取全部考试的列表成功", examVos);
} catch (Exception e) { } catch (Exception e) {
// 捕获异常,并打印异常信息。
e.printStackTrace(); e.printStackTrace();
// 将异常信息封装到ResultVO对象中并返回。
resultVO = new ResultVO<>(-1, "获取全部考试的列表失败", null); resultVO = new ResultVO<>(-1, "获取全部考试的列表失败", null);
} }
return resultVO; return resultVO;
@ -149,15 +175,19 @@ public class ExamController {
@GetMapping("/question/type/list") @GetMapping("/question/type/list")
@ApiOperation("获取问题列表,按照单选、多选和判断题分类返回") @ApiOperation("获取问题列表,按照单选、多选和判断题分类返回")
ResultVO<ExamQuestionTypeVo> getExamQuestionTypeList() { ResultVO<ExamQuestionTypeVo> getExamQuestionTypeList() {
// 获取问题的分类列表 // 获取问题的分类列表
ResultVO<ExamQuestionTypeVo> resultVO; ResultVO<ExamQuestionTypeVo> resultVO;
try { try {
// 调用examService的getExamQuestionType方法获取问题分类列表。
ExamQuestionTypeVo examQuestionTypeVo = examService.getExamQuestionType(); ExamQuestionTypeVo examQuestionTypeVo = examService.getExamQuestionType();
// 如果获取成功,则返回成功的结果。
resultVO = new ResultVO<>(0, "获取问题列表成功", examQuestionTypeVo); resultVO = new ResultVO<>(0, "获取问题列表成功", examQuestionTypeVo);
} catch (Exception e) { } catch (Exception e) {
// 如果获取失败,则打印异常信息,并返回失败的结果。
e.printStackTrace(); e.printStackTrace();
resultVO = new ResultVO<>(-1, "获取问题列表失败", null); resultVO = new ResultVO<>(-1, "获取问题列表失败", null);
} }
// 返回结果。
return resultVO; return resultVO;
} }
@ -170,19 +200,22 @@ public class ExamController {
@PostMapping("/create") @PostMapping("/create")
@ApiOperation("创建考试") @ApiOperation("创建考试")
ResultVO<Exam> createExam(@RequestBody ExamCreateVo examCreateVo, HttpServletRequest request) { ResultVO<Exam> createExam(@RequestBody ExamCreateVo examCreateVo, HttpServletRequest request) {
// 从前端传参数过来,在这里完成考试的入库 // 定义一个ResultVO类型的变量用于存放最终要返回给客户端的结果对象其泛型参数指定为Exam表示包含新创建考试相关信息的结果封装
ResultVO<Exam> resultVO; ResultVO<Exam> resultVO;
// 从HttpServletRequest对象中获取用户ID信息通常这个用户ID是在请求处理的前置环节比如拦截器中设置到请求属性中的用于标识创建这个考试的用户是谁
String userId = (String) request.getAttribute("user_id"); String userId = (String) request.getAttribute("user_id");
try { try {
// 调用ExamService的create方法将创建考试的视图对象examCreateVo和获取到的用户ID传递进去由服务层实现将考试记录数据保存到数据库等具体的创建逻辑操作返回创建好的Exam对象代表新创建的考试信息
Exam exam = examService.create(examCreateVo, userId); Exam exam = examService.create(examCreateVo, userId);
// 如果创建成功创建一个表示成功的ResultVO对象状态码设置为0表示创建操作成功消息设置为"创建考试成功"并将创建好的考试对象放入ResultVO对象中返回给客户端
resultVO = new ResultVO<>(0, "创建考试成功", exam); resultVO = new ResultVO<>(0, "创建考试成功", exam);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
// 如果在创建过程中出现异常创建一个表示创建失败的ResultVO对象状态码设置为 -1表示创建操作失败消息设置为"创建考试失败"数据部分设置为null
resultVO = new ResultVO<>(-1, "创建考试失败", null); resultVO = new ResultVO<>(-1, "创建考试失败", null);
} }
return resultVO; return resultVO;
} }
/** /**
* @Description: 使examService.updateExam(),ResultVO, * @Description: 使examService.updateExam(),ResultVO,
* @param examVo * @param examVo
@ -192,19 +225,23 @@ public class ExamController {
@PostMapping("/update") @PostMapping("/update")
@ApiOperation("更新考试") @ApiOperation("更新考试")
ResultVO<Exam> updateExam(@RequestBody ExamVo examVo, HttpServletRequest request) { ResultVO<Exam> updateExam(@RequestBody ExamVo examVo, HttpServletRequest request) {
// 从前端传参数过来,在这里完成考试的入库 // 从前端传参数过来,在这里完成考试的入库
ResultVO<Exam> resultVO; ResultVO<Exam> resultVO;
// 获取当前用户id。
String userId = (String) request.getAttribute("user_id"); String userId = (String) request.getAttribute("user_id");
try { try {
// 调用service层更新考试。
Exam exam = examService.update(examVo, userId); Exam exam = examService.update(examVo, userId);
// 返回更新成功的resultVO。
resultVO = new ResultVO<>(0, "更新考试成功", exam); resultVO = new ResultVO<>(0, "更新考试成功", exam);
} catch (Exception e) { } catch (Exception e) {
// 打印异常信息。
e.printStackTrace(); e.printStackTrace();
// 返回更新失败的resultVO。
resultVO = new ResultVO<>(-1, "更新考试失败", null); resultVO = new ResultVO<>(-1, "更新考试失败", null);
} }
return resultVO; return resultVO;
} }
/** /**
* @Description: * @Description:
* @return ResultVO<List<ExamCardVo>> * @return ResultVO<List<ExamCardVo>>
@ -212,18 +249,21 @@ public class ExamController {
@GetMapping("/card/list") @GetMapping("/card/list")
@ApiOperation("获取考试列表,适配前端卡片列表") @ApiOperation("获取考试列表,适配前端卡片列表")
ResultVO<List<ExamCardVo>> getExamCardList() { ResultVO<List<ExamCardVo>> getExamCardList() {
// 获取考试列表卡片 // 获取考试列表卡片
ResultVO<List<ExamCardVo>> resultVO; ResultVO<List<ExamCardVo>> resultVO;
try { try {
// 调用examService的getExamCardList方法获取考试列表卡片。
List<ExamCardVo> examCardVoList = examService.getExamCardList(); List<ExamCardVo> examCardVoList = examService.getExamCardList();
// 如果获取数据成功创建一个表示成功的ResultVO对象状态码设置为0表示获取考试列表卡片成功消息设置为"获取考试列表卡片成功"并将获取到的考试卡片列表数据放入ResultVO对象中以便返回给客户端进行展示。
resultVO = new ResultVO<>(0, "获取考试列表卡片成功", examCardVoList); resultVO = new ResultVO<>(0, "获取考试列表卡片成功", examCardVoList);
} catch (Exception e) { } catch (Exception e) {
// 如果获取失败,则打印异常信息,并返回失败的结果。
e.printStackTrace(); e.printStackTrace();
// 创建一个表示获取失败的ResultVO对象状态码设置为 -1表示获取考试列表卡片失败消息可根据业务实际情况设置为相应的提示语数据部分设置为null因为没有成功获取到有效的考试卡片列表数据。
resultVO = new ResultVO<>(-1, "获取考试列表卡片失败", null); resultVO = new ResultVO<>(-1, "获取考试列表卡片失败", null);
} }
return resultVO; return resultVO;
} }
/** /**
* @Description: id * @Description: id
* @param id id * @param id id
@ -232,17 +272,19 @@ public class ExamController {
@GetMapping("/detail/{id}") @GetMapping("/detail/{id}")
@ApiOperation("根据考试的id获取考试详情") @ApiOperation("根据考试的id获取考试详情")
ResultVO<ExamDetailVo> getExamDetail(@PathVariable String id) { ResultVO<ExamDetailVo> getExamDetail(@PathVariable String id) {
// 根据id获取考试详情 // 根据id获取考试详情先定义一个用于存放最终要返回给客户端的ResultVO<ExamDetailVo>类型的结果对象,后续根据查询数据的情况进行赋值操作。
ResultVO<ExamDetailVo> resultVO; ResultVO<ExamDetailVo> resultVO;
try { try {
// 调用ExamService的getExamDetail方法将接收到的考卷唯一标识符id传递进去由服务层实现从数据库或者其他数据源根据该ID查询对应考卷详细信息的逻辑返回一个ExamDetailVo对象代表该考卷的所有详细信息。
ExamDetailVo examDetail = examService.getExamDetail(id); ExamDetailVo examDetail = examService.getExamDetail(id);
// 如果获取详细信息成功创建一个表示成功的ResultVO对象状态码设置为0表示获取考试详情成功消息设置为"获取考试详情成功"并将获取到的考卷详细信息对象放入ResultVO对象中以便返回给客户端进行展示。
resultVO = new ResultVO<>(0, "获取考试详情成功", examDetail); resultVO = new ResultVO<>(0, "获取考试详情成功", examDetail);
} catch (Exception e) { } catch (Exception e) {
// 如果在获取考卷详细信息的过程中出现异常创建一个表示获取失败的ResultVO对象状态码设置为 -1表示获取考试详情失败消息可根据业务实际情况设置为相应的提示语数据部分设置为null因为没有成功获取到有效的考卷详细信息。
resultVO = new ResultVO<>(-1, "获取考试详情失败", null); resultVO = new ResultVO<>(-1, "获取考试详情失败", null);
} }
return resultVO; return resultVO;
} }
/** /**
* @Description: 使examService.finishExam,ResultVO, * @Description: 使examService.finishExam,ResultVO,
* @param examId id * @param examId id
@ -253,20 +295,23 @@ public class ExamController {
@PostMapping("/finish/{examId}") @PostMapping("/finish/{examId}")
@ApiOperation("根据用户提交的答案对指定id的考试判分") @ApiOperation("根据用户提交的答案对指定id的考试判分")
ResultVO<ExamRecord> finishExam(@PathVariable String examId, @RequestBody HashMap<String, List<String>> answersMap, HttpServletRequest request) { ResultVO<ExamRecord> finishExam(@PathVariable String examId, @RequestBody HashMap<String, List<String>> answersMap, HttpServletRequest request) {
// 定义一个用于存放结果的ResultVO<ExamRecord>类型的数据结构,后续根据评分操作的成功与否以及获取到的相关数据进行赋值,用于最终返回给客户端展示评分结果。
ResultVO<ExamRecord> resultVO; ResultVO<ExamRecord> resultVO;
try { try {
// 拦截器里设置上的用户id // 拦截器里设置上的用户id从HttpServletRequest对象中获取用户ID属性值该用户ID用于标识当前提交答案并进行评分的用户是后续业务逻辑处理如记录答题记录归属、判断是否有权限答题等的重要依据。
String userId = (String) request.getAttribute("user_id"); String userId = (String) request.getAttribute("user_id");
// 下面根据用户提交的信息进行判分,返回用户的得分情况 // 下面根据用户提交的信息进行判分返回用户的得分情况调用ExamService的judge方法传入获取到的用户ID、考试唯一标识符examId以及用户提交的答案集合answersMap由服务层实现具体的评分逻辑比如对比答案、计算得分等操作并返回一个ExamRecord对象包含了评分后的成绩记录等详细信息。
ExamRecord examRecord = examService.judge(userId, examId, answersMap); ExamRecord examRecord = examService.judge(userId, examId, answersMap);
resultVO = new ResultVO<>(0, "考卷提交成功", examRecord); // 封装成绩记录到最终结果中创建一个表示评分成功的ResultVO对象状态码设置为0表示考卷提交评分成功消息设置为"考卷提交成功"并将包含成绩记录的ExamRecord对象放入ResultVO对象中以便返回给客户端展示评分结果。
resultVO = new ResultVO<>(0, "考卷提交成功", examRecord);// 封装成绩记录到最终结果中
} catch (Exception e) { } catch (Exception e) {
// 如果在评分过程中出现异常,打印异常堆栈信息,方便开发人员排查问题,查看是答案解析出错还是其他业务逻辑环节出现的错误导致评分失败。
e.printStackTrace(); e.printStackTrace();
// 创建一个表示评分失败的ResultVO对象状态码设置为 -1表示考卷提交评分失败消息可根据业务实际情况设置为相应的提示语数据部分设置为null因为没有成功获取到有效的评分成绩记录。
resultVO = new ResultVO<>(-1, "考卷提交失败", null); resultVO = new ResultVO<>(-1, "考卷提交失败", null);
} }
return resultVO; return resultVO;
} }
/** /**
* @Description: 使examService.getExamRecordList,ResultVO, * @Description: 使examService.getExamRecordList,ResultVO,
* @param request id * @param request id
@ -275,20 +320,23 @@ public class ExamController {
@GetMapping("/record/list") @GetMapping("/record/list")
@ApiOperation("获取当前用户的考试记录") @ApiOperation("获取当前用户的考试记录")
ResultVO<List<ExamRecordVo>> getExamRecordList(HttpServletRequest request) { ResultVO<List<ExamRecordVo>> getExamRecordList(HttpServletRequest request) {
// 定义一个用于存放结果的ResultVO<List<ExamRecordVo>>类型的数据结构,后续根据查询用户考试记录操作的成功与否以及获取到的相关数据进行赋值,用于最终返回给客户端展示查询结果。
ResultVO<List<ExamRecordVo>> resultVO; ResultVO<List<ExamRecordVo>> resultVO;
try { try {
// 拦截器里设置上的用户id // 拦截器里设置上的用户id从HttpServletRequest对象中获取用户ID属性值该用户ID用于明确要查询其考试记录的目标用户是服务层准确获取对应数据的关键依据。
String userId = (String) request.getAttribute("user_id"); String userId = (String) request.getAttribute("user_id");
// 下面根据用户账号拿到他(她所有的考试信息)注意要用VO封装下 // 下面根据用户账号拿到他所有的考试信息注意要用VO封装下调用ExamService的getExamRecordList方法传入获取到的用户ID由服务层实现从数据库或者其他数据源获取该用户所有历史考试记录数据的逻辑并将其整理封装成List<ExamRecordVo>类型的列表返回每个ExamRecordVo对象包含了如时间、得分等详细信息。
List<ExamRecordVo> examRecordVoList = examService.getExamRecordList(userId); List<ExamRecordVo> examRecordVoList = examService.getExamRecordList(userId);
resultVO = new ResultVO<>(0, "获取考试记录成功", examRecordVoList); // 封装查询得到的信息到最终结果中创建一个表示获取成功的ResultVO对象状态码设置为0表示获取考试记录成功消息设置为"获取考试记录成功"并将获取到的用户考试记录列表数据放入ResultVO对象中以便返回给客户端展示历史考试记录情况。
resultVO = new ResultVO<>(0, "获取考试记录成功", examRecordVoList);//封装查询得到的信息到最终结果中;
} catch (Exception e) { } catch (Exception e) {
// 如果在获取用户考试记录数据的过程中出现异常,打印异常堆栈信息,方便开发人员排查问题,查看是数据源查询出错还是数据封装等环节出现的错误导致获取失败。
e.printStackTrace(); e.printStackTrace();
// 创建一个表示获取失败的ResultVO对象状态码设置为 -1表示获取考试记录失败消息可根据业务实际情况设置为相应的提示语数据部分设置为null因为没有成功获取到有效的用户考试记录数据。
resultVO = new ResultVO<>(-1, "获取考试记录失败", null); resultVO = new ResultVO<>(-1, "获取考试记录失败", null);
} }
return resultVO; return resultVO;//返回封装好的 数据结构
} }
/** /**
* @Description: 使examService.getExamRecordDetail,ResultVO,id * @Description: 使examService.getExamRecordDetail,ResultVO,id
* @param recordId id * @param recordId id
@ -297,14 +345,24 @@ public class ExamController {
@GetMapping("/record/detail/{recordId}") @GetMapping("/record/detail/{recordId}")
@ApiOperation("根据考试记录id获取考试记录详情") @ApiOperation("根据考试记录id获取考试记录详情")
ResultVO<RecordDetailVo> getExamRecordDetail(@PathVariable String recordId) { ResultVO<RecordDetailVo> getExamRecordDetail(@PathVariable String recordId) {
// 定义一个用于存放结果的ResultVO<RecordDetailVo>类型的数据结构,后续根据查询测验详细情况操作的成功与否以及获取到的相关数据进行赋值,用于最终返回给客户端展示查询结果。
ResultVO<RecordDetailVo> resultVO; ResultVO<RecordDetailVo> resultVO;
try { try {
// 调用ExamService的getRecordDetail方法将接收到的测验记录唯一标识符recordId传递进去由服务层实现从数据库或者其他数据源根据该ID查询对应测验详细信息的逻辑返回一个RecordDetailVo对象代表该次测验的所有详细信息。
RecordDetailVo recordDetailVo = examService.getRecordDetail(recordId); RecordDetailVo recordDetailVo = examService.getRecordDetail(recordId);
resultVO = new ResultVO<>(0, "获取考试记录详情成功", recordDetailVo); // 封装查询得到的信息到最终结果中创建一个表示获取成功的ResultVO对象状态码设置为0表示获取考试记录详情成功消息设置为"获取考试记录详情成功"并将获取到的测验详细信息对象放入ResultVO对象中以便返回给客户端展示该次测验的详细情况。
resultVO = new ResultVO<>(0, "获取考试记录详情成功", recordDetailVo);//封装查询得到的信息到最终结果中;
} catch (Exception e) { } catch (Exception e) {
// 如果在获取测验详细信息的过程中出现异常,打印异常堆栈信息,方便开发人员排查问题,查看是数据源查询出错还是数据解析等环节出现的错误导致获取失败。
e.printStackTrace(); e.printStackTrace();
// 创建一个ResultVO对象表示操作失败
// 状态码设置为-1表示获取考试记录详情失败
// 消息设置为"获取考试记录详情失败"
// 由于查询失败详细信息对象设置为null
resultVO = new ResultVO<>(-1, "获取考试记录详情失败", null); resultVO = new ResultVO<>(-1, "获取考试记录详情失败", null);
} }
// 返回封装好的ResultVO对象给客户端
// 客户端可以根据状态码和消息判断操作是否成功,并根据详细信息对象获取测验的详细记录信息
return resultVO; return resultVO;
} }
} }

@ -40,36 +40,76 @@ public class UploadDownloadController {
// return FileTransUtil.uploadFile(uploadfile, "/root/" + File.separator + uploadfile.getOriginalFilename()); // return FileTransUtil.uploadFile(uploadfile, "/root/" + File.separator + uploadfile.getOriginalFilename());
// } // }
/**
*
*
* @param dir
* @param uploadfile
* @return String
*/
@ApiOperation("单文件上传,支持同时传入参数") @ApiOperation("单文件上传,支持同时传入参数")
@PostMapping("/api/upload/singleAndparas") @PostMapping("/api/upload/singleAndparas")
public String uploadFileSingle(@RequestParam("dir") String dir, @RequestParam("file") MultipartFile uploadfile) { public String uploadFileSingle(@RequestParam("dir") String dir, @RequestParam("file") MultipartFile uploadfile) {
return FileTransUtil.uploadFile(uploadfile, dir); return FileTransUtil.uploadFile(uploadfile, dir);
} }
/**
* Model
*
* @param model UploadModel2
* @return String
*/
@ApiOperation("单文件上传,支持同时传入参数,Model") @ApiOperation("单文件上传,支持同时传入参数,Model")
@PostMapping("/upload/single/model") @PostMapping("/upload/single/model")
public String singleUploadFileModel(@ModelAttribute("model") UploadModel2 model) { public String singleUploadFileModel(@ModelAttribute("model") UploadModel2 model) {
return FileTransUtil.uploadFile(model.getFile(), model.getDir()); return FileTransUtil.uploadFile(model.getFile(), model.getDir());
} }
/**
*
*
* @param dir
* @param uploadfiles
* @return String
*/
@ApiOperation("多文件上传,支持同时传入参数") @ApiOperation("多文件上传,支持同时传入参数")
@PostMapping("upload/multiAndparas") @PostMapping("upload/multiAndparas")
public String uploadFileMulti(@RequestParam("dir") String dir, @RequestParam("files") MultipartFile[] uploadfiles) { public String uploadFileMulti(@RequestParam("dir") String dir, @RequestParam("files") MultipartFile[] uploadfiles) {
return FileTransUtil.uploadFiles(uploadfiles, dir); return FileTransUtil.uploadFiles(uploadfiles, dir);
} }
/**
*
*
* @param model UploadModel
* @return String
*/
@ApiOperation("多文件上传,支持同时传入参数") @ApiOperation("多文件上传,支持同时传入参数")
@PostMapping(value = "/upload/multi/model") @PostMapping(value = "/upload/multi/model")
public String multiUploadFileModel(@ModelAttribute(("model")) UploadModel model) { public String multiUploadFileModel(@ModelAttribute(("model")) UploadModel model) {
return FileTransUtil.uploadFiles(model.getFiles(), model.getDir()); return FileTransUtil.uploadFiles(model.getFiles(), model.getDir());
} }
/**
* Get
*
* @param filePath
* @return ResponseEntity<InputStreamResource>
* @throws IOException
*/
@ApiOperation("Get下载文件") @ApiOperation("Get下载文件")
@GetMapping(value = "/download/get") @GetMapping(value = "/download/get")
public ResponseEntity<InputStreamResource> downloadFileGet(@RequestParam String filePath) throws IOException { public ResponseEntity<InputStreamResource> downloadFileGet(@RequestParam String filePath) throws IOException {
return FileTransUtil.downloadFile(filePath); return FileTransUtil.downloadFile(filePath);
} }
/**
* Post
*
* @param downloadQo DownloadQo
* @return ResponseEntity<InputStreamResource>
* @throws IOException
*/
@ApiOperation("Post下载文件") @ApiOperation("Post下载文件")
@PostMapping(value = "/download/post") @PostMapping(value = "/download/post")
public ResponseEntity<InputStreamResource> downloadFilePost(@RequestBody DownloadQo downloadQo) throws IOException { public ResponseEntity<InputStreamResource> downloadFilePost(@RequestBody DownloadQo downloadQo) throws IOException {

@ -29,6 +29,12 @@ public class UserController {
@Autowired @Autowired
private UserService userService; private UserService userService;
/**
*
*
* @param registerDTO RegisterDTO
* @return ResultVO<User>
*/
@PostMapping("/register") @PostMapping("/register")
@ApiOperation("注册") @ApiOperation("注册")
ResultVO<User> register(@RequestBody RegisterDTO registerDTO) { ResultVO<User> register(@RequestBody RegisterDTO registerDTO) {
@ -44,6 +50,12 @@ public class UserController {
return resultVO; return resultVO;
} }
/**
* ,token
*
* @param loginQo LoginQo
* @return ResultVO<String>
*/
@PostMapping("/login") @PostMapping("/login")
@ApiOperation("根据用户名或邮箱登录,登录成功返回token") @ApiOperation("根据用户名或邮箱登录,登录成功返回token")
ResultVO<String> login(@RequestBody LoginQo loginQo) { // 这里不用手机号是因为手机号和用户名难以进行格式区分,而用户名和 ResultVO<String> login(@RequestBody LoginQo loginQo) { // 这里不用手机号是因为手机号和用户名难以进行格式区分,而用户名和
@ -60,23 +72,50 @@ public class UserController {
return resultVO; return resultVO;
} }
/**
*
*
* @param request HttpServletRequest
* @return ResultVO<UserVo>
*/
@GetMapping("/user-info") @GetMapping("/user-info")
@ApiOperation("获取用户信息") @ApiOperation("获取用户信息")
// 根据请求获取用户信息
ResultVO<UserVo> getUserInfo(HttpServletRequest request) { ResultVO<UserVo> getUserInfo(HttpServletRequest request) {
// 从请求中获取用户ID
String userId = (String) request.getAttribute("user_id"); String userId = (String) request.getAttribute("user_id");
// 根据用户ID获取用户信息
UserVo userVo = userService.getUserInfo(userId); UserVo userVo = userService.getUserInfo(userId);
// 返回用户信息
return new ResultVO<>(ResultEnum.GET_INFO_SUCCESS.getCode(), ResultEnum.GET_INFO_SUCCESS.getMessage(), userVo); return new ResultVO<>(ResultEnum.GET_INFO_SUCCESS.getCode(), ResultEnum.GET_INFO_SUCCESS.getMessage(), userVo);
} }
/**
*
*
* @param request HttpServletRequest
* @return ResultVO<UserInfoVo>
*/
@GetMapping("/info") @GetMapping("/info")
@ApiOperation("获取用户的详细信息,包括个人信息页面和操作权限") @ApiOperation("获取用户的详细信息,包括个人信息页面和操作权限")
// 获取用户信息的接口
ResultVO<UserInfoVo> getInfo(HttpServletRequest request) { ResultVO<UserInfoVo> getInfo(HttpServletRequest request) {
// 打印进入接口的日志
System.out.println("进入/user/info的获取用户信息的接口"); System.out.println("进入/user/info的获取用户信息的接口");
// 获取用户ID
String userId = (String) request.getAttribute("user_id"); String userId = (String) request.getAttribute("user_id");
// 调用userService获取用户信息
UserInfoVo userInfoVo = userService.getInfo(userId); UserInfoVo userInfoVo = userService.getInfo(userId);
// 返回结果
return new ResultVO<>(ResultEnum.GET_INFO_SUCCESS.getCode(), ResultEnum.GET_INFO_SUCCESS.getMessage(), userInfoVo); return new ResultVO<>(ResultEnum.GET_INFO_SUCCESS.getCode(), ResultEnum.GET_INFO_SUCCESS.getMessage(), userInfoVo);
} }
/**
*
*
* @param request HttpServletRequest
* @return String
*/
@GetMapping("/test") @GetMapping("/test")
@ApiOperation("测试接口") @ApiOperation("测试接口")
String test(HttpServletRequest request) { String test(HttpServletRequest request) {

@ -8,11 +8,26 @@ package lsgwr.exam.dto;
import lombok.Data; import lombok.Data;
/**
*
*/
@Data @Data
public class RegisterDTO { public class RegisterDTO {
/**
*
*/
private String email; private String email;
/**
*
*/
private String password; private String password;
/**
*
*/
private String password2; private String password2;
/**
*
*/
private String mobile; private String mobile;
/** /**
* *

@ -11,17 +11,29 @@ import lombok.Data;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.GeneratedValue; import javax.persistence.GeneratedValue;
import javax.persistence.Id; import javax.persistence.Id;
/**
*
* ID
*/
@Data @Data
@Entity @Entity
public class Action { public class Action {
/**
* ID
*/
@Id @Id
@GeneratedValue @GeneratedValue
private Integer actionId; private Integer actionId;
/**
*
*/
private String actionName; private String actionName;
/**
*
*/
private String actionDescription; private String actionDescription;
/**
*
*/
private Boolean defaultCheck; private Boolean defaultCheck;
} }

@ -4,51 +4,108 @@
* @date : 2019/5/14 07:42 * @date : 2019/5/14 07:42
* @email : liangshanguang2@gmail.com * @email : liangshanguang2@gmail.com
***********************************************************/ ***********************************************************/
// 定义包名,用于组织类文件,避免命名冲突
package lsgwr.exam.entity; package lsgwr.exam.entity;
// 导入Jackson库的JsonFormat注解用于JSON序列化时自定义日期格式
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
// 导入Lombok库的Data注解用于自动生成getter、setter、equals、hashCode和toString方法
import lombok.Data; import lombok.Data;
// 导入Hibernate的DynamicUpdate注解用于在实体更新时只更新发生变化的字段
import org.hibernate.annotations.DynamicUpdate; import org.hibernate.annotations.DynamicUpdate;
// 导入JPA的Entity注解用于声明该类是一个JPA实体类
import javax.persistence.Entity; import javax.persistence.Entity;
// 导入JPA的Id注解用于声明该类中的某个字段作为主键
import javax.persistence.Id; import javax.persistence.Id;
// 导入Java的Date类用于表示日期和时间
import java.util.Date; import java.util.Date;
@Entity @Entity
@Data @Data
@DynamicUpdate @DynamicUpdate
/**
*
*/
public class Exam { public class Exam {
// 使用JPA的@Id注解声明该字段为主键
/**
* ID
*/
@Id @Id
private String examId; private String examId;
/**
*
*/
private String examName; private String examName;
/**
*
*/
private String examAvatar; private String examAvatar;
/**
*
*/
private String examDescription; private String examDescription;
/**
* IDID
*/
private String examQuestionIds; private String examQuestionIds;
/**
* ID
*/
private String examQuestionIdsRadio; private String examQuestionIdsRadio;
/**
* ID
*/
private String examQuestionIdsCheck; private String examQuestionIdsCheck;
/**
* ID
*/
private String examQuestionIdsJudge; private String examQuestionIdsJudge;
/**
*
*/
private Integer examScore; private Integer examScore;
/**
*
*/
private Integer examScoreRadio; private Integer examScoreRadio;
/**
*
*/
private Integer examScoreCheck; private Integer examScoreCheck;
/**
*
*/
private Integer examScoreJudge; private Integer examScoreJudge;
/**
* ID
*/
private String examCreatorId; private String examCreatorId;
/**
*
*/
private Integer examTimeLimit; private Integer examTimeLimit;
/**
* 使Jackson@JsonFormat
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date examStartDate; private Date examStartDate;
/**
*
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date examEndDate; private Date examEndDate;
/** /**
* , Java * Java
* 使Jackson@JsonFormat便
*/ */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime; private Date createTime;
/** /**
* Java * Java
* @DynamicUpdate * 使Hibernate@DynamicUpdate
* 使Jackson@JsonFormat便
*/ */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date updateTime; private Date updateTime;

@ -7,42 +7,44 @@
package lsgwr.exam.entity; package lsgwr.exam.entity;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;// 引入Jackson库用于日期格式化的注解
import lombok.Data; import lombok.Data;// 引入Lombok库用于简化Java实体类的编写如自动生成getter和setter方法
import javax.persistence.Entity; import javax.persistence.Entity;// 引入JPA注解用于标识这是一个实体类并映射到数据库中的一张表
// 引入JPA注解用于标识实体类的主键字段
import javax.persistence.Id; import javax.persistence.Id;
import java.util.Date; import java.util.Date;
// 使用@Data注解自动生成getter和setter方法以及toString、equals和hashCode方法
@Data @Data
// 使用@Entity注解标识这是一个JPA实体类
@Entity @Entity
public class ExamRecord { public class ExamRecord {
/** /**
* *
*/ */
@Id @Id
private String examRecordId; private String examRecordId;
/** /**
* id * ID
*/ */
private String examId; private String examId;
/** /**
* (_-), * 线_线-
*/ */
private String answerOptionIds; private String answerOptionIds;
/** /**
* userid * IDID
*/ */
private String examJoinerId; private String examJoinerId;
/** /**
* *
*/ */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date examJoinDate; private Date examJoinDate;
/** /**
* () *
*/ */
private Integer examTimeCost; private Integer examTimeCost;
/** /**
@ -50,7 +52,7 @@ public class ExamRecord {
*/ */
private Integer examJoinScore; private Integer examJoinScore;
/** /**
* *
*/ */
private Integer examResultLevel; private Integer examResultLevel;
} }

@ -7,18 +7,31 @@
package lsgwr.exam.entity; package lsgwr.exam.entity;
import lombok.Data; import lombok.Data;// 引入Lombok库中的@Data注解用于自动生成getter、setter、toString、equals和hashCode方法
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Entity;// 引入JPAJava Persistence API中的@Entity注解标识这是一个实体类与数据库中的表相对应
import javax.persistence.GeneratedValue;// 引入JPA中的@GeneratedValue注解用于指定主键的生成策略这里未明确指定策略将使用默认策略
import javax.persistence.Id;// 引入JPA中的@Id注解标识实体类的主键字段
// 使用@Data注解自动生成getter、setter等方法
@Data @Data
// 使用@Entity注解标识这是一个JPA实体类
@Entity @Entity
public class ExamRecordLevel { /**
*
*/
public class ExamRecordLevel {
/**
* ID@Id@GeneratedValue
*/
@Id @Id
@GeneratedValue @GeneratedValue
private Integer examRecordLevelId; private Integer examRecordLevelId;
/**
*
*/
private String examRecordLevelName; private String examRecordLevelName;
/**
*
*/
private String examRecordLevelDescription; private String examRecordLevelDescription;
} }

@ -12,16 +12,28 @@ import javax.persistence.Entity;
import javax.persistence.GeneratedValue; import javax.persistence.GeneratedValue;
import javax.persistence.Id; import javax.persistence.Id;
/**
*
*/
@Data @Data
@Entity @Entity
public class Page { public class Page {
/**
* ID@Id@GeneratedValue
*/
@Id @Id
@GeneratedValue @GeneratedValue
private Integer pageId; private Integer pageId;
/**
*
*/
private String pageName; private String pageName;
/**
*
*/
private String pageDescription; private String pageDescription;
/**
* ID
*/
private String actionIds; private String actionIds;
} }

@ -14,21 +14,54 @@ import org.hibernate.annotations.DynamicUpdate;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.Id; import javax.persistence.Id;
import java.util.Date; import java.util.Date;
/**
*
* getter/setter
*/
@Data @Data
@Entity @Entity
@DynamicUpdate @DynamicUpdate
public class Question { public class Question {
/**
* id
*/
@Id @Id
private String questionId; private String questionId;
/**
*
*/
private String questionName; private String questionName;
/**
*
*/
private Integer questionScore; private Integer questionScore;
/**
* id
*/
private String questionCreatorId; private String questionCreatorId;
/**
* id
*/
private Integer questionLevelId; private Integer questionLevelId;
/**
* id
*/
private Integer questionTypeId; private Integer questionTypeId;
/**
* id
*/
private Integer questionCategoryId; private Integer questionCategoryId;
/**
*
*/
private String questionDescription; private String questionDescription;
/**
* idA,B,C,D
*/
private String questionOptionIds; private String questionOptionIds;
/**
* idA
*/
private String questionAnswerOptionIds; private String questionAnswerOptionIds;
/** /**
* , Java * , Java

@ -13,19 +13,27 @@ import lombok.Data;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.GeneratedValue; import javax.persistence.GeneratedValue;
import javax.persistence.Id; import javax.persistence.Id;
/**
*
*/
@Data @Data
@Entity @Entity
public class QuestionCategory { public class QuestionCategory {
/**
* id
*/
@Id @Id
@GeneratedValue @GeneratedValue
@JsonProperty("id") @JsonProperty("id")
private Integer questionCategoryId; private Integer questionCategoryId;
/**
*
*/
@JsonProperty("name") @JsonProperty("name")
private String questionCategoryName; private String questionCategoryName;
/**
*
*/
@JsonProperty("description") @JsonProperty("description")
private String questionCategoryDescription; private String questionCategoryDescription;
} }

@ -14,17 +14,27 @@ import javax.persistence.Entity;
import javax.persistence.GeneratedValue; import javax.persistence.GeneratedValue;
import javax.persistence.Id; import javax.persistence.Id;
/**
*
*/
@Entity @Entity
@Data @Data
public class QuestionLevel { public class QuestionLevel {
/**
* ID
*/
@Id @Id
@GeneratedValue @GeneratedValue
@JsonProperty("id") @JsonProperty("id")
private Integer questionLevelId; private Integer questionLevelId;
/**
*
*/
@JsonProperty("name") @JsonProperty("name")
private String questionLevelName; private String questionLevelName;
/**
*
*/
@JsonProperty("description") @JsonProperty("description")
private String questionLevelDescription; private String questionLevelDescription;
} }

@ -11,12 +11,23 @@ import lombok.Data;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.Id; import javax.persistence.Id;
/**
*
*/
@Data @Data
@Entity @Entity
public class QuestionOption { public class QuestionOption {
/**
* ABCD
*/
@Id @Id
private String questionOptionId; private String questionOptionId;
/**
*
*/
private String questionOptionContent; private String questionOptionContent;
/**
*
*/
private String questionOptionDescription; private String questionOptionDescription;
} }

@ -14,17 +14,28 @@ import javax.persistence.Entity;
import javax.persistence.GeneratedValue; import javax.persistence.GeneratedValue;
import javax.persistence.Id; import javax.persistence.Id;
/**
* QuestionType
* ID
*/
@Data @Data
@Entity @Entity
public class QuestionType { public class QuestionType {
/**
* ID
*/
@Id @Id
@GeneratedValue @GeneratedValue
@JsonProperty("id") @JsonProperty("id")
private Integer questionTypeId; private Integer questionTypeId;
/**
*
*/
@JsonProperty("name") @JsonProperty("name")
private String questionTypeName; private String questionTypeName;
/**
*
*/
@JsonProperty("description") @JsonProperty("description")
private String questionTypeDescription; private String questionTypeDescription;
} }

@ -13,14 +13,31 @@ import javax.persistence.Entity;
import javax.persistence.GeneratedValue; import javax.persistence.GeneratedValue;
import javax.persistence.Id; import javax.persistence.Id;
/**
*
* ID
*/
@Data @Data
@Entity @Entity
public class Role { public class Role {
/**
* ID
* @Id
*/
@Id @Id
@GeneratedValue @GeneratedValue
private Integer roleId; private Integer roleId;
/**
*
*/
private String roleName; private String roleName;
/**
*
*/
private String roleDescription; private String roleDescription;
/**
*
*/
private String roleDetail; private String roleDetail;
/** /**
* 访(-) * 访(-)

@ -14,20 +14,49 @@ import org.hibernate.annotations.DynamicUpdate;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.Id; import javax.persistence.Id;
import java.util.Date; import java.util.Date;
/**
*
*/
@Data @Data
@Entity @Entity
@DynamicUpdate @DynamicUpdate
public class User { public class User {
/**
* id
*/
@Id @Id
private String userId; private String userId;
/**
*
*/
private String userUsername; private String userUsername;
/**
*
*/
private String userNickname; private String userNickname;
/**
*
*/
private String userPassword; private String userPassword;
/**
* id
*/
private Integer userRoleId; private Integer userRoleId;
/**
*
*/
private String userAvatar; private String userAvatar;
/**
*
*/
private String userDescription; private String userDescription;
/**
*
*/
private String userEmail; private String userEmail;
/**
*
*/
private String userPhone; private String userPhone;
/** /**
* , Java * , Java

@ -3,18 +3,18 @@ package lsgwr.exam.enums;
import lombok.Getter; import lombok.Getter;
/** /**
* * @Description:
* @author liangshanguang
*/ */
@Getter @Getter
public enum LoginTypeEnum { public enum LoginTypeEnum {
/** /**
* 12 * @Description:
* 12
*/ */
USERNAME(1, "用户名"), USERNAME(1, "用户名"),
EMAIL(2, "邮箱"); EMAIL(2, "邮箱");
// 构造函数用于初始化code和description
LoginTypeEnum(Integer type, String name) { LoginTypeEnum(Integer type, String name) {
this.type = type; this.type = type;
this.name = name; this.name = name;

@ -8,17 +8,16 @@ package lsgwr.exam.enums;
import lombok.Getter; import lombok.Getter;
/**
* @Description :
*/
@Getter @Getter
public enum QuestionEnum { public enum QuestionEnum {
/**
*
*/
RADIO(1, "单选题"), RADIO(1, "单选题"),
CHECK(2, "多选题"), CHECK(2, "多选题"),
JUDGE(3, "判断题"); JUDGE(3, "判断题");
// 构造函数用于初始化id和role
QuestionEnum(Integer id, String role) { QuestionEnum(Integer id, String role) {
this.id = id; this.id = id;
this.role = role; this.role = role;

@ -2,6 +2,9 @@ package lsgwr.exam.enums;
import lombok.Getter; import lombok.Getter;
/**
* @Description :
*/
@Getter @Getter
public enum ResultEnum { public enum ResultEnum {
// 下面是本项目用到的所有错误码 // 下面是本项目用到的所有错误码
@ -17,6 +20,11 @@ public enum ResultEnum {
ORDER_UPDATE_ERR(15, "考试更新异常"), ORDER_UPDATE_ERR(15, "考试更新异常"),
ORDER_DETAIL_EMPTY(16, "用户详情为空"); ORDER_DETAIL_EMPTY(16, "用户详情为空");
/**
* @Description: codemessage
* @param code
* @param message
*/
ResultEnum(Integer code, String message) { ResultEnum(Integer code, String message) {
this.code = code; this.code = code;
this.message = message; this.message = message;

@ -8,6 +8,9 @@ package lsgwr.exam.enums;
import lombok.Getter; import lombok.Getter;
/**
* @Description:
*/
@Getter @Getter
public enum RoleEnum { public enum RoleEnum {
@ -18,7 +21,11 @@ public enum RoleEnum {
TEACHER(2, "教师"), TEACHER(2, "教师"),
STUDENT(3, "学生"); STUDENT(3, "学生");
/**
* @Description: codemessage
* @param id id
* @param role
*/
RoleEnum(Integer id, String role) { RoleEnum(Integer id, String role) {
this.id = id; this.id = id;
this.role = role; this.role = role;

@ -9,15 +9,32 @@ package lsgwr.exam.exception;
import lsgwr.exam.enums.ResultEnum; import lsgwr.exam.enums.ResultEnum;
import lombok.Getter; import lombok.Getter;
/**
*
*/
@Getter @Getter
public class ExamException extends RuntimeException { public class ExamException extends RuntimeException {
/**
*
*/
private Integer code; private Integer code;
/**
*
*
* @param resultEnum ResultEnum
*/
public ExamException(ResultEnum resultEnum) { public ExamException(ResultEnum resultEnum) {
super(resultEnum.getMessage()); super(resultEnum.getMessage());
this.code = resultEnum.getCode(); this.code = resultEnum.getCode();
} }
/**
*
*
* @param code
* @param message
*/
public ExamException( Integer code, String message) { public ExamException( Integer code, String message) {
super(message); super(message);
this.code = code; this.code = code;

@ -23,6 +23,10 @@ import java.io.PrintWriter;
* *
* @author liangshanguang * @author liangshanguang
*/ */
/**
* Token
*/
@Component @Component
public class LoginInterceptor implements HandlerInterceptor { public class LoginInterceptor implements HandlerInterceptor {

@ -13,5 +13,8 @@ import lombok.NoArgsConstructor;
@AllArgsConstructor @AllArgsConstructor
@NoArgsConstructor @NoArgsConstructor
public class DownloadQo { public class DownloadQo {
/**
*
*/
String path; String path;
} }

@ -10,6 +10,9 @@ import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
/**
*
*/
@Data @Data
@AllArgsConstructor @AllArgsConstructor
@NoArgsConstructor @NoArgsConstructor

@ -12,6 +12,9 @@ import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
/**
*
*/
@Data @Data
@AllArgsConstructor @AllArgsConstructor
@NoArgsConstructor @NoArgsConstructor

@ -12,6 +12,9 @@ import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
/**
*
*/
@Data @Data
@AllArgsConstructor @AllArgsConstructor
@NoArgsConstructor @NoArgsConstructor

@ -9,5 +9,8 @@ package lsgwr.exam.repository;
import lsgwr.exam.entity.ExamRecordLevel; import lsgwr.exam.entity.ExamRecordLevel;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
/**
* ExamRecordLevelRepositoryJpaRepositoryExamRecordLevel
*/
public interface ExamRecordLevelRepository extends JpaRepository<ExamRecordLevel, Integer> { public interface ExamRecordLevelRepository extends JpaRepository<ExamRecordLevel, Integer> {
} }

@ -1,9 +1,3 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019-05-14 08:23
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.repository; package lsgwr.exam.repository;
import lsgwr.exam.entity.ExamRecord; import lsgwr.exam.entity.ExamRecord;
@ -11,6 +5,9 @@ import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List; import java.util.List;
/**
*
*/
public interface ExamRecordRepository extends JpaRepository<ExamRecord, String> { public interface ExamRecordRepository extends JpaRepository<ExamRecord, String> {
/** /**
* *

@ -12,7 +12,11 @@ import org.springframework.data.jpa.repository.Query;
import java.util.List; import java.util.List;
/**
* ExamRepositoryJpaRepositoryExam
*/
public interface ExamRepository extends JpaRepository<Exam, String> { public interface ExamRepository extends JpaRepository<Exam, String> {
// 使用JPQL查询语句查询Exam实体类按照updateTime降序排列
@Query("select e from Exam e order by e.updateTime desc") @Query("select e from Exam e order by e.updateTime desc")
List<Exam> findAll(); List<Exam> findAll();
} }

@ -8,6 +8,8 @@ package lsgwr.exam.repository;
import lsgwr.exam.entity.Page; import lsgwr.exam.entity.Page;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
/**
*
*/
public interface PageRepository extends JpaRepository<Page, Integer> { public interface PageRepository extends JpaRepository<Page, Integer> {
} }

@ -8,6 +8,8 @@ package lsgwr.exam.repository;
import lsgwr.exam.entity.QuestionCategory; import lsgwr.exam.entity.QuestionCategory;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
/**
*
*/
public interface QuestionCategoryRepository extends JpaRepository<QuestionCategory, Integer> { public interface QuestionCategoryRepository extends JpaRepository<QuestionCategory, Integer> {
} }

@ -8,6 +8,8 @@ package lsgwr.exam.repository;
import lsgwr.exam.entity.QuestionLevel; import lsgwr.exam.entity.QuestionLevel;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
/**
*
*/
public interface QuestionLevelRepository extends JpaRepository<QuestionLevel, Integer> { public interface QuestionLevelRepository extends JpaRepository<QuestionLevel, Integer> {
} }

@ -8,6 +8,8 @@ package lsgwr.exam.repository;
import lsgwr.exam.entity.QuestionOption; import lsgwr.exam.entity.QuestionOption;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
/**
*
*/
public interface QuestionOptionRepository extends JpaRepository<QuestionOption, String> { public interface QuestionOptionRepository extends JpaRepository<QuestionOption, String> {
} }

@ -11,9 +11,22 @@ import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.Query;
import java.util.List; import java.util.List;
/**
*
*/
public interface QuestionRepository extends JpaRepository<Question, String> { public interface QuestionRepository extends JpaRepository<Question, String> {
/**
* ID
*
* @param id ID
* @return
*/
List<Question> findByQuestionTypeId(Integer id); List<Question> findByQuestionTypeId(Integer id);
/**
*
*
* @return
*/
@Query("select q from Question q order by q.updateTime desc") @Query("select q from Question q order by q.updateTime desc")
List<Question> findAll(); List<Question> findAll();
} }

@ -8,6 +8,8 @@ package lsgwr.exam.repository;
import lsgwr.exam.entity.QuestionType; import lsgwr.exam.entity.QuestionType;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
/**
*
*/
public interface QuestionTypeRepository extends JpaRepository<QuestionType, Integer> { public interface QuestionTypeRepository extends JpaRepository<QuestionType, Integer> {
} }

@ -9,5 +9,8 @@ package lsgwr.exam.repository;
import lsgwr.exam.entity.Role; import lsgwr.exam.entity.Role;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
/**
*
*/
public interface RoleRepository extends JpaRepository<Role, Integer> { public interface RoleRepository extends JpaRepository<Role, Integer> {
} }

@ -8,7 +8,9 @@ package lsgwr.exam.repository;
import lsgwr.exam.entity.User; import lsgwr.exam.entity.User;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
/**
*
*/
public interface UserRepository extends JpaRepository<User, String> { public interface UserRepository extends JpaRepository<User, String> {
/** /**
* *

@ -4,15 +4,15 @@
* @date : 2019-05-28 08:05 * @date : 2019-05-28 08:05
* @email : liangshanguang2@gmail.com * @email : liangshanguang2@gmail.com
***********************************************************/ ***********************************************************/
package lsgwr.exam.service; package lsgwr.exam.service;// 定义了接口所属的包名
import lsgwr.exam.entity.Exam; import lsgwr.exam.entity.Exam;// 导入了实体类Exam可能包含考试的基本信息
import lsgwr.exam.entity.ExamRecord; import lsgwr.exam.entity.ExamRecord;// 导入了实体类ExamRecord可能包含考试记录的详细信息
import lsgwr.exam.vo.*; import lsgwr.exam.vo.*;// 导入了VO对象VO是值对象用于在不同层之间传递数据
import java.util.HashMap;
import java.util.List;
import java.util.HashMap;// 导入了HashMap用于存储键值对
import java.util.List;// 导入了List用于存储一系列对象
// 定义了一个名为ExamService的接口
public interface ExamService { public interface ExamService {
/** /**
* *

@ -10,8 +10,8 @@ import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import lsgwr.exam.entity.*; import lsgwr.exam.entity.*;
import lsgwr.exam.enums.QuestionEnum; import lsgwr.exam.enums.QuestionEnum;
import lsgwr.exam.service.ExamService;
import lsgwr.exam.repository.*; import lsgwr.exam.repository.*;
import lsgwr.exam.service.ExamService;
import lsgwr.exam.vo.*; import lsgwr.exam.vo.*;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -19,6 +19,9 @@ import org.springframework.stereotype.Service;
import javax.transaction.Transactional; import javax.transaction.Transactional;
import java.util.*; import java.util.*;
/**
*
*/
@Service @Service
@Transactional @Transactional
public class ExamServiceImpl implements ExamService { public class ExamServiceImpl implements ExamService {
@ -39,6 +42,17 @@ public class ExamServiceImpl implements ExamService {
private final QuestionOptionRepository questionOptionRepository; private final QuestionOptionRepository questionOptionRepository;
/**
*
* @param questionRepository
* @param userRepository
* @param questionLevelRepository
* @param questionTypeRepository
* @param questionCategoryRepository
* @param questionOptionRepository
* @param examRepository
* @param examRecordRepository
*/
public ExamServiceImpl(QuestionRepository questionRepository, UserRepository userRepository, QuestionLevelRepository questionLevelRepository, QuestionTypeRepository questionTypeRepository, QuestionCategoryRepository questionCategoryRepository, QuestionOptionRepository questionOptionRepository, ExamRepository examRepository, ExamRecordRepository examRecordRepository) { public ExamServiceImpl(QuestionRepository questionRepository, UserRepository userRepository, QuestionLevelRepository questionLevelRepository, QuestionTypeRepository questionTypeRepository, QuestionCategoryRepository questionCategoryRepository, QuestionOptionRepository questionOptionRepository, ExamRepository examRepository, ExamRecordRepository examRecordRepository) {
this.questionRepository = questionRepository; this.questionRepository = questionRepository;
this.userRepository = userRepository; this.userRepository = userRepository;
@ -50,16 +64,26 @@ public class ExamServiceImpl implements ExamService {
this.examRecordRepository = examRecordRepository; this.examRecordRepository = examRecordRepository;
} }
/**
* @decription :
* return List<QuestionVo>
*/
@Override @Override
public List<QuestionVo> getQuestionAll() { public List<QuestionVo> getQuestionAll() {
List<Question> questionList = questionRepository.findAll(); List<Question> questionList = questionRepository.findAll();
return getQuestionVos(questionList); return getQuestionVos(questionList);
} }
/**
* Vo
*
* @param questionList
* @return Vo
*/
private List<QuestionVo> getQuestionVos(List<Question> questionList) { private List<QuestionVo> getQuestionVos(List<Question> questionList) {
// 需要自定义的question列表 // 需要自定义的question列表
List<QuestionVo> questionVoList = new ArrayList<>(); List<QuestionVo> questionVoList = new ArrayList<>();
// 循环完成每个属性的定制 // 循环完成每个属性的定制
for (Question question : questionList) { for (Question question : questionList) {
QuestionVo questionVo = getQuestionVo(question); QuestionVo questionVo = getQuestionVo(question);
questionVoList.add(questionVo); questionVoList.add(questionVo);
@ -69,9 +93,9 @@ public class ExamServiceImpl implements ExamService {
private QuestionVo getQuestionVo(Question question) { private QuestionVo getQuestionVo(Question question) {
QuestionVo questionVo = new QuestionVo(); QuestionVo questionVo = new QuestionVo();
// 先复制能复制的属性 // 先复制能复制的属性
BeanUtils.copyProperties(question, questionVo); BeanUtils.copyProperties(question, questionVo);
// 设置问题的创建者 // 设置问题的创建者
questionVo.setQuestionCreator( questionVo.setQuestionCreator(
Objects.requireNonNull( Objects.requireNonNull(
userRepository.findById( userRepository.findById(
@ -79,7 +103,7 @@ public class ExamServiceImpl implements ExamService {
).orElse(null) ).orElse(null)
).getUserUsername()); ).getUserUsername());
// 设置问题的难度 // 设置问题的难度
questionVo.setQuestionLevel( questionVo.setQuestionLevel(
Objects.requireNonNull( Objects.requireNonNull(
questionLevelRepository.findById( questionLevelRepository.findById(
@ -87,7 +111,7 @@ public class ExamServiceImpl implements ExamService {
).orElse(null) ).orElse(null)
).getQuestionLevelDescription()); ).getQuestionLevelDescription());
// 设置题目的类别,比如单选、多选、判断等 // 设置题目的类别,比如单选、多选、判断等
questionVo.setQuestionType( questionVo.setQuestionType(
Objects.requireNonNull( Objects.requireNonNull(
questionTypeRepository.findById( questionTypeRepository.findById(
@ -95,7 +119,7 @@ public class ExamServiceImpl implements ExamService {
).orElse(null) ).orElse(null)
).getQuestionTypeDescription()); ).getQuestionTypeDescription());
// 设置题目分类,比如数学、语文、英语、生活、人文等 // 设置题目分类,比如数学、语文、英语、生活、人文等
questionVo.setQuestionCategory( questionVo.setQuestionCategory(
Objects.requireNonNull( Objects.requireNonNull(
questionCategoryRepository.findById( questionCategoryRepository.findById(
@ -104,20 +128,20 @@ public class ExamServiceImpl implements ExamService {
).getQuestionCategoryName() ).getQuestionCategoryName()
); );
// 选项的自定义Vo列表 // 选项的自定义Vo列表
List<QuestionOptionVo> optionVoList = new ArrayList<>(); List<QuestionOptionVo> optionVoList = new ArrayList<>();
// 获得所有的选项列表 // 获得所有的选项列表
List<QuestionOption> optionList = questionOptionRepository.findAllById( List<QuestionOption> optionList = questionOptionRepository.findAllById(
Arrays.asList(question.getQuestionOptionIds().split("-")) Arrays.asList(question.getQuestionOptionIds().split("-"))
); );
// 获取所有的答案列表optionList中每个option的isAnswer选项 // 获取所有的答案列表optionList中每个option的isAnswer选项
List<QuestionOption> answerList = questionOptionRepository.findAllById( List<QuestionOption> answerList = questionOptionRepository.findAllById(
Arrays.asList(question.getQuestionAnswerOptionIds().split("-")) Arrays.asList(question.getQuestionAnswerOptionIds().split("-"))
); );
// 根据选项和答案的id相同设置optionVo的isAnswer属性 // 根据选项和答案的id相同设置optionVo的isAnswer属性
for (QuestionOption option : optionList) { for (QuestionOption option : optionList) {
QuestionOptionVo optionVo = new QuestionOptionVo(); QuestionOptionVo optionVo = new QuestionOptionVo();
BeanUtils.copyProperties(option, optionVo); BeanUtils.copyProperties(option, optionVo);
@ -129,14 +153,14 @@ public class ExamServiceImpl implements ExamService {
optionVoList.add(optionVo); optionVoList.add(optionVo);
} }
// 设置题目的所有选项 // 设置题目的所有选项
questionVo.setQuestionOptionVoList(optionVoList); questionVo.setQuestionOptionVoList(optionVoList);
return questionVo; return questionVo;
} }
@Override @Override
public QuestionVo updateQuestion(QuestionVo questionVo) { public QuestionVo updateQuestion(QuestionVo questionVo) {
// 1.把需要的属性都设置好 // 1.把需要的属性都设置好
StringBuilder questionAnswerOptionIds = new StringBuilder(); StringBuilder questionAnswerOptionIds = new StringBuilder();
List<QuestionOption> questionOptionList = new ArrayList<>(); List<QuestionOption> questionOptionList = new ArrayList<>();
List<QuestionOptionVo> questionOptionVoList = questionVo.getQuestionOptionVoList(); List<QuestionOptionVo> questionOptionVoList = questionVo.getQuestionOptionVoList();
@ -148,26 +172,26 @@ public class ExamServiceImpl implements ExamService {
questionOptionList.add(questionOption); questionOptionList.add(questionOption);
if (questionOptionVo.getAnswer()) { if (questionOptionVo.getAnswer()) {
if (i != size - 1) { if (i != size - 1) {
// 把更新后的答案的id加上去,记得用-连到一起 // 把更新后的答案的id加上去,记得用-连到一起
questionAnswerOptionIds.append(questionOptionVo.getQuestionOptionId()).append("-"); questionAnswerOptionIds.append(questionOptionVo.getQuestionOptionId()).append("-");
} else { } else {
// 最后一个不需要用-连接 // 最后一个不需要用-连接
questionAnswerOptionIds.append(questionOptionVo.getQuestionOptionId()); questionAnswerOptionIds.append(questionOptionVo.getQuestionOptionId());
} }
} }
} }
// 1.更新问题 // 1.更新问题
Question question = questionRepository.findById(questionVo.getQuestionId()).orElse(null); Question question = questionRepository.findById(questionVo.getQuestionId()).orElse(null);
assert question != null; assert question != null;
BeanUtils.copyProperties(questionVo, question); BeanUtils.copyProperties(questionVo, question);
question.setQuestionAnswerOptionIds(questionAnswerOptionIds.toString()); question.setQuestionAnswerOptionIds(questionAnswerOptionIds.toString());
questionRepository.save(question); questionRepository.save(question);
// 2.更新所有的option // 2.更新所有的option
questionOptionRepository.saveAll(questionOptionList); questionOptionRepository.saveAll(questionOptionList);
// 返回更新后的问题,方便前端局部刷新 // 返回更新后的问题,方便前端局部刷新
return getQuestionVo(question); return getQuestionVo(question);
} }
@ -175,58 +199,64 @@ public class ExamServiceImpl implements ExamService {
public void questionCreate(QuestionCreateVo questionCreateVo) { public void questionCreate(QuestionCreateVo questionCreateVo) {
// 问题创建 // 问题创建
Question question = new Question(); Question question = new Question();
// 把能复制的属性都复制过来 // 把能复制的属性都复制过来
BeanUtils.copyProperties(questionCreateVo, question); BeanUtils.copyProperties(questionCreateVo, question);
// 设置下questionOptionIds和questionAnswerOptionIds需要自己用Hutool生成下 // 设置下questionOptionIds和questionAnswerOptionIds需要自己用Hutool生成下
List<QuestionOption> questionOptionList = new ArrayList<>(); List<QuestionOption> questionOptionList = new ArrayList<>();
List<QuestionOptionCreateVo> questionOptionCreateVoList = questionCreateVo.getQuestionOptionCreateVoList(); List<QuestionOptionCreateVo> questionOptionCreateVoList = questionCreateVo.getQuestionOptionCreateVoList();
for (QuestionOptionCreateVo questionOptionCreateVo : questionOptionCreateVoList) { for (QuestionOptionCreateVo questionOptionCreateVo : questionOptionCreateVoList) {
QuestionOption questionOption = new QuestionOption(); QuestionOption questionOption = new QuestionOption();
// 设置选项的的内容 // 设置选项的的内容
questionOption.setQuestionOptionContent(questionOptionCreateVo.getQuestionOptionContent()); questionOption.setQuestionOptionContent(questionOptionCreateVo.getQuestionOptionContent());
// 设置选项的id // 设置选项的id
questionOption.setQuestionOptionId(IdUtil.simpleUUID()); questionOption.setQuestionOptionId(IdUtil.simpleUUID());
questionOptionList.add(questionOption); questionOptionList.add(questionOption);
} }
// 把选项都存起来然后才能用于下面设置Question的questionOptionIds和questionAnswerOptionIds // 把选项都存起来然后才能用于下面设置Question的questionOptionIds和questionAnswerOptionIds
questionOptionRepository.saveAll(questionOptionList); questionOptionRepository.saveAll(questionOptionList);
String questionOptionIds = ""; String questionOptionIds = "";
String questionAnswerOptionIds = ""; String questionAnswerOptionIds = "";
// 经过上面的saveAll方法所有的option的主键id都已经持久化了 // 经过上面的saveAll方法所有的option的主键id都已经持久化了
for (int i = 0; i < questionOptionCreateVoList.size(); i++) { for (int i = 0; i < questionOptionCreateVoList.size(); i++) {
// 获取指定选项 // 获取指定选项
QuestionOptionCreateVo questionOptionCreateVo = questionOptionCreateVoList.get(i); QuestionOptionCreateVo questionOptionCreateVo = questionOptionCreateVoList.get(i);
// 获取保存后的指定对象 // 获取保存后的指定对象
QuestionOption questionOption = questionOptionList.get(i); QuestionOption questionOption = questionOptionList.get(i);
questionOptionIds += questionOption.getQuestionOptionId() + "-"; questionOptionIds += questionOption.getQuestionOptionId() + "-";
if (questionOptionCreateVo.getAnswer()) { if (questionOptionCreateVo.getAnswer()) {
// 如果是答案的话 // 如果是答案的话
questionAnswerOptionIds += questionOption.getQuestionOptionId() + "-"; questionAnswerOptionIds += questionOption.getQuestionOptionId() + "-";
} }
} }
// 把字符串最后面的"-"给去掉 // 把字符串最后面的"-"给去掉
questionAnswerOptionIds = replaceLastSeparator(questionAnswerOptionIds); questionAnswerOptionIds = replaceLastSeparator(questionAnswerOptionIds);
questionOptionIds = replaceLastSeparator(questionOptionIds); questionOptionIds = replaceLastSeparator(questionOptionIds);
// 设置选项id组成的字符串 // 设置选项id组成的字符串
question.setQuestionOptionIds(questionOptionIds); question.setQuestionOptionIds(questionOptionIds);
// 设置答案选项id组成的字符串 // 设置答案选项id组成的字符串
question.setQuestionAnswerOptionIds(questionAnswerOptionIds); question.setQuestionAnswerOptionIds(questionAnswerOptionIds);
// 自己生成问题的id // 自己生成问题的id
question.setQuestionId(IdUtil.simpleUUID()); question.setQuestionId(IdUtil.simpleUUID());
// 先把创建时间和更新时间每次都取当前时间吧 // 先把创建时间和更新时间每次都取当前时间吧
question.setCreateTime(new Date()); question.setCreateTime(new Date());
question.setUpdateTime(new Date()); question.setUpdateTime(new Date());
// 保存问题到数据库 // 保存问题到数据库
questionRepository.save(question); questionRepository.save(question);
} }
@Override @Override
// 重写父类方法,获取问题选择列表
public QuestionSelectionVo getSelections() { public QuestionSelectionVo getSelections() {
// 创建问题选择对象
QuestionSelectionVo questionSelectionVo = new QuestionSelectionVo(); QuestionSelectionVo questionSelectionVo = new QuestionSelectionVo();
// 设置问题类别列表
questionSelectionVo.setQuestionCategoryList(questionCategoryRepository.findAll()); questionSelectionVo.setQuestionCategoryList(questionCategoryRepository.findAll());
// 设置问题等级列表
questionSelectionVo.setQuestionLevelList(questionLevelRepository.findAll()); questionSelectionVo.setQuestionLevelList(questionLevelRepository.findAll());
// 设置问题类型列表
questionSelectionVo.setQuestionTypeList(questionTypeRepository.findAll()); questionSelectionVo.setQuestionTypeList(questionTypeRepository.findAll());
// 返回问题选择对象
return questionSelectionVo; return questionSelectionVo;
} }
@ -245,10 +275,15 @@ public class ExamServiceImpl implements ExamService {
@Override @Override
public QuestionDetailVo getQuestionDetail(String id) { public QuestionDetailVo getQuestionDetail(String id) {
// 根据id查询问题
Question question = questionRepository.findById(id).orElse(null); Question question = questionRepository.findById(id).orElse(null);
// 创建问题详情对象
QuestionDetailVo questionDetailVo = new QuestionDetailVo(); QuestionDetailVo questionDetailVo = new QuestionDetailVo();
// 设置问题id
questionDetailVo.setId(id); questionDetailVo.setId(id);
// 设置问题名称
questionDetailVo.setName(question.getQuestionName()); questionDetailVo.setName(question.getQuestionName());
// 设置问题描述
questionDetailVo.setDescription(question.getQuestionDescription()); questionDetailVo.setDescription(question.getQuestionDescription());
// 问题类型,单选题/多选题/判断题 // 问题类型,单选题/多选题/判断题
questionDetailVo.setType( questionDetailVo.setType(
@ -258,10 +293,10 @@ public class ExamServiceImpl implements ExamService {
).orElse(null) ).orElse(null)
).getQuestionTypeDescription() ).getQuestionTypeDescription()
); );
// 获取当前问题的选项 // 获取当前问题的选项
String optionIdsStr = trimMiddleLine(question.getQuestionOptionIds()); String optionIdsStr = trimMiddleLine(question.getQuestionOptionIds());
String[] optionIds = optionIdsStr.split("-"); String[] optionIds = optionIdsStr.split("-");
// 获取选项列表 // 获取选项列表
List<QuestionOption> optionList = questionOptionRepository.findAllById(Arrays.asList(optionIds)); List<QuestionOption> optionList = questionOptionRepository.findAllById(Arrays.asList(optionIds));
questionDetailVo.setOptions(optionList); questionDetailVo.setOptions(optionList);
return questionDetailVo; return questionDetailVo;
@ -274,14 +309,14 @@ public class ExamServiceImpl implements ExamService {
} }
private List<ExamVo> getExamVos(List<Exam> examList) { private List<ExamVo> getExamVos(List<Exam> examList) {
// 需要自定义的exam列表 // 需要自定义的exam列表
List<ExamVo> examVoList = new ArrayList<>(); List<ExamVo> examVoList = new ArrayList<>();
// 循环完成每个属性的定制 // 循环完成每个属性的定制
for (Exam exam : examList) { for (Exam exam : examList) {
ExamVo examVo = new ExamVo(); ExamVo examVo = new ExamVo();
// 先尽量复制能复制的所有属性 // 先尽量复制能复制的所有属性
BeanUtils.copyProperties(exam, examVo); BeanUtils.copyProperties(exam, examVo);
// 设置问题的创建者 // 设置问题的创建者
examVo.setExamCreator( examVo.setExamCreator(
Objects.requireNonNull( Objects.requireNonNull(
userRepository.findById( userRepository.findById(
@ -290,7 +325,7 @@ public class ExamServiceImpl implements ExamService {
).getUserUsername() ).getUserUsername()
); );
// 获取所有单选题列表并赋值到ExamVo的属性ExamQuestionSelectVoRadioList上 // 获取所有单选题列表并赋值到ExamVo的属性ExamQuestionSelectVoRadioList上
List<ExamQuestionSelectVo> radioQuestionVoList = new ArrayList<>(); List<ExamQuestionSelectVo> radioQuestionVoList = new ArrayList<>();
List<Question> radioQuestionList = questionRepository.findAllById( List<Question> radioQuestionList = questionRepository.findAllById(
Arrays.asList(exam.getExamQuestionIdsRadio().split("-")) Arrays.asList(exam.getExamQuestionIdsRadio().split("-"))
@ -298,12 +333,12 @@ public class ExamServiceImpl implements ExamService {
for (Question question : radioQuestionList) { for (Question question : radioQuestionList) {
ExamQuestionSelectVo radioQuestionVo = new ExamQuestionSelectVo(); ExamQuestionSelectVo radioQuestionVo = new ExamQuestionSelectVo();
BeanUtils.copyProperties(question, radioQuestionVo); BeanUtils.copyProperties(question, radioQuestionVo);
radioQuestionVo.setChecked(true); // 考试中的问题肯定被选中的 radioQuestionVo.setChecked(true); // 考试中的问题肯定被选中的
radioQuestionVoList.add(radioQuestionVo); radioQuestionVoList.add(radioQuestionVo);
} }
examVo.setExamQuestionSelectVoRadioList(radioQuestionVoList); examVo.setExamQuestionSelectVoRadioList(radioQuestionVoList);
// 获取所有多选题列表并赋值到ExamVo的属性ExamQuestionSelectVoCheckList上 // 获取所有多选题列表并赋值到ExamVo的属性ExamQuestionSelectVoCheckList上
List<ExamQuestionSelectVo> checkQuestionVoList = new ArrayList<>(); List<ExamQuestionSelectVo> checkQuestionVoList = new ArrayList<>();
List<Question> checkQuestionList = questionRepository.findAllById( List<Question> checkQuestionList = questionRepository.findAllById(
Arrays.asList(exam.getExamQuestionIdsCheck().split("-")) Arrays.asList(exam.getExamQuestionIdsCheck().split("-"))
@ -311,12 +346,12 @@ public class ExamServiceImpl implements ExamService {
for (Question question : checkQuestionList) { for (Question question : checkQuestionList) {
ExamQuestionSelectVo checkQuestionVo = new ExamQuestionSelectVo(); ExamQuestionSelectVo checkQuestionVo = new ExamQuestionSelectVo();
BeanUtils.copyProperties(question, checkQuestionVo); BeanUtils.copyProperties(question, checkQuestionVo);
checkQuestionVo.setChecked(true); // 考试中的问题肯定被选中的 checkQuestionVo.setChecked(true); // 考试中的问题肯定被选中的
checkQuestionVoList.add(checkQuestionVo); checkQuestionVoList.add(checkQuestionVo);
} }
examVo.setExamQuestionSelectVoCheckList(checkQuestionVoList); examVo.setExamQuestionSelectVoCheckList(checkQuestionVoList);
// 获取所有多选题列表并赋值到ExamVo的属性ExamQuestionSelectVoJudgeList上 // 获取所有多选题列表并赋值到ExamVo的属性ExamQuestionSelectVoJudgeList上
List<ExamQuestionSelectVo> judgeQuestionVoList = new ArrayList<>(); List<ExamQuestionSelectVo> judgeQuestionVoList = new ArrayList<>();
List<Question> judgeQuestionList = questionRepository.findAllById( List<Question> judgeQuestionList = questionRepository.findAllById(
Arrays.asList(exam.getExamQuestionIdsJudge().split("-")) Arrays.asList(exam.getExamQuestionIdsJudge().split("-"))
@ -324,7 +359,7 @@ public class ExamServiceImpl implements ExamService {
for (Question question : judgeQuestionList) { for (Question question : judgeQuestionList) {
ExamQuestionSelectVo judgeQuestionVo = new ExamQuestionSelectVo(); ExamQuestionSelectVo judgeQuestionVo = new ExamQuestionSelectVo();
BeanUtils.copyProperties(question, judgeQuestionVo); BeanUtils.copyProperties(question, judgeQuestionVo);
judgeQuestionVo.setChecked(true); // 考试中的问题肯定被选中的 judgeQuestionVo.setChecked(true); // 考试中的问题肯定被选中的
judgeQuestionVoList.add(judgeQuestionVo); judgeQuestionVoList.add(judgeQuestionVo);
} }
examVo.setExamQuestionSelectVoJudgeList(judgeQuestionVoList); examVo.setExamQuestionSelectVoJudgeList(judgeQuestionVoList);
@ -340,7 +375,7 @@ public class ExamServiceImpl implements ExamService {
@Override @Override
public ExamQuestionTypeVo getExamQuestionType() { public ExamQuestionTypeVo getExamQuestionType() {
ExamQuestionTypeVo examQuestionTypeVo = new ExamQuestionTypeVo(); ExamQuestionTypeVo examQuestionTypeVo = new ExamQuestionTypeVo();
// 获取所有单选题列表并赋值到ExamVo的属性ExamQuestionSelectVoRadioList上 // 获取所有单选题列表并赋值到ExamVo的属性ExamQuestionSelectVoRadioList上
List<ExamQuestionSelectVo> radioQuestionVoList = new ArrayList<>(); List<ExamQuestionSelectVo> radioQuestionVoList = new ArrayList<>();
List<Question> radioQuestionList = questionRepository.findByQuestionTypeId(QuestionEnum.RADIO.getId()); List<Question> radioQuestionList = questionRepository.findByQuestionTypeId(QuestionEnum.RADIO.getId());
for (Question question : radioQuestionList) { for (Question question : radioQuestionList) {
@ -350,7 +385,7 @@ public class ExamServiceImpl implements ExamService {
} }
examQuestionTypeVo.setExamQuestionSelectVoRadioList(radioQuestionVoList); examQuestionTypeVo.setExamQuestionSelectVoRadioList(radioQuestionVoList);
// 获取所有多选题列表并赋值到ExamVo的属性ExamQuestionSelectVoCheckList上 // 获取所有多选题列表并赋值到ExamVo的属性ExamQuestionSelectVoCheckList上
List<ExamQuestionSelectVo> checkQuestionVoList = new ArrayList<>(); List<ExamQuestionSelectVo> checkQuestionVoList = new ArrayList<>();
List<Question> checkQuestionList = questionRepository.findByQuestionTypeId(QuestionEnum.CHECK.getId()); List<Question> checkQuestionList = questionRepository.findByQuestionTypeId(QuestionEnum.CHECK.getId());
for (Question question : checkQuestionList) { for (Question question : checkQuestionList) {
@ -360,7 +395,7 @@ public class ExamServiceImpl implements ExamService {
} }
examQuestionTypeVo.setExamQuestionSelectVoCheckList(checkQuestionVoList); examQuestionTypeVo.setExamQuestionSelectVoCheckList(checkQuestionVoList);
// 获取所有多选题列表并赋值到ExamVo的属性ExamQuestionSelectVoJudgeList上 // 获取所有多选题列表并赋值到ExamVo的属性ExamQuestionSelectVoJudgeList上
List<ExamQuestionSelectVo> judgeQuestionVoList = new ArrayList<>(); List<ExamQuestionSelectVo> judgeQuestionVoList = new ArrayList<>();
List<Question> judgeQuestionList = questionRepository.findByQuestionTypeId(QuestionEnum.JUDGE.getId()); List<Question> judgeQuestionList = questionRepository.findByQuestionTypeId(QuestionEnum.JUDGE.getId());
for (Question question : judgeQuestionList) { for (Question question : judgeQuestionList) {
@ -374,7 +409,7 @@ public class ExamServiceImpl implements ExamService {
@Override @Override
public Exam create(ExamCreateVo examCreateVo, String userId) { public Exam create(ExamCreateVo examCreateVo, String userId) {
// 在线考试系统创建 // 在线考试系统创建
Exam exam = new Exam(); Exam exam = new Exam();
BeanUtils.copyProperties(examCreateVo, exam); BeanUtils.copyProperties(examCreateVo, exam);
exam.setExamId(IdUtil.simpleUUID()); exam.setExamId(IdUtil.simpleUUID());
@ -382,32 +417,50 @@ public class ExamServiceImpl implements ExamService {
exam.setCreateTime(new Date()); exam.setCreateTime(new Date());
exam.setUpdateTime(new Date()); exam.setUpdateTime(new Date());
// Todo:这两个日志后面是要在前端传入的,这里暂时定为当前日期 // Todo:这两个日志后面是要在前端传入的,这里暂时定为当前日期
// 设置考试开始时间和结束时间
exam.setExamStartDate(new Date()); exam.setExamStartDate(new Date());
exam.setExamEndDate(new Date()); exam.setExamEndDate(new Date());
// 初始化选择题、判断题和单选题的id字符串
String radioIdsStr = ""; String radioIdsStr = "";
String checkIdsStr = ""; String checkIdsStr = "";
String judgeIdsStr = ""; String judgeIdsStr = "";
// 获取选择题、判断题和单选题的列表
List<ExamQuestionSelectVo> radios = examCreateVo.getRadios(); List<ExamQuestionSelectVo> radios = examCreateVo.getRadios();
List<ExamQuestionSelectVo> checks = examCreateVo.getChecks(); List<ExamQuestionSelectVo> checks = examCreateVo.getChecks();
List<ExamQuestionSelectVo> judges = examCreateVo.getJudges(); List<ExamQuestionSelectVo> judges = examCreateVo.getJudges();
// 初始化选择题、判断题和单选题的计数器
int radioCnt = 0, checkCnt = 0, judgeCnt = 0; int radioCnt = 0, checkCnt = 0, judgeCnt = 0;
// 遍历单选题列表
for (ExamQuestionSelectVo radio : radios) { for (ExamQuestionSelectVo radio : radios) {
// 如果单选题被选中
if (radio.getChecked()) { if (radio.getChecked()) {
// 将单选题的id添加到字符串中
radioIdsStr += radio.getQuestionId() + "-"; radioIdsStr += radio.getQuestionId() + "-";
// 单选题计数器加1
radioCnt++; radioCnt++;
} }
} }
// 去掉最后一个分隔符
radioIdsStr = replaceLastSeparator(radioIdsStr); radioIdsStr = replaceLastSeparator(radioIdsStr);
// 遍历判断题列表
for (ExamQuestionSelectVo check : checks) { for (ExamQuestionSelectVo check : checks) {
// 如果判断题被选中
if (check.getChecked()) { if (check.getChecked()) {
// 将判断题的id添加到字符串中
checkIdsStr += check.getQuestionId() + "-"; checkIdsStr += check.getQuestionId() + "-";
// 判断题计数器加1
checkCnt++; checkCnt++;
} }
} }
// 去掉最后一个分隔符
checkIdsStr = replaceLastSeparator(checkIdsStr); checkIdsStr = replaceLastSeparator(checkIdsStr);
// 遍历选择题列表
for (ExamQuestionSelectVo judge : judges) { for (ExamQuestionSelectVo judge : judges) {
// 如果选择题被选中
if (judge.getChecked()) { if (judge.getChecked()) {
// 将选择题的id添加到字符串中
judgeIdsStr += judge.getQuestionId() + "-"; judgeIdsStr += judge.getQuestionId() + "-";
// 选择题计数器加1
judgeCnt++; judgeCnt++;
} }
} }
@ -427,49 +480,64 @@ public class ExamServiceImpl implements ExamService {
@Override @Override
public Exam update(ExamVo examVo, String userId) { public Exam update(ExamVo examVo, String userId) {
// 创建一个新的Exam对象
Exam exam = new Exam(); Exam exam = new Exam();
// 将examVo中的属性值复制到exam对象中
BeanUtils.copyProperties(examVo, exam); BeanUtils.copyProperties(examVo, exam);
exam.setExamCreatorId(userId); // 考试的更新人为最新的创建人 // 设置考试更新人为最新的创建人
exam.setUpdateTime(new Date()); // 考试的更新日期要记录下 exam.setExamCreatorId(userId);
// 记录考试更新日期
exam.setUpdateTime(new Date());
// 初始化选择题、判断题、单选题的id字符串
String radioIdsStr = ""; String radioIdsStr = "";
String checkIdsStr = ""; String checkIdsStr = "";
String judgeIdsStr = ""; String judgeIdsStr = "";//djfndiosbchjdshjiowceduikmn
// 获取选择题、判断题、单选题的列表
List<ExamQuestionSelectVo> radios = examVo.getExamQuestionSelectVoRadioList(); List<ExamQuestionSelectVo> radios = examVo.getExamQuestionSelectVoRadioList();
List<ExamQuestionSelectVo> checks = examVo.getExamQuestionSelectVoCheckList(); List<ExamQuestionSelectVo> checks = examVo.getExamQuestionSelectVoCheckList();
List<ExamQuestionSelectVo> judges = examVo.getExamQuestionSelectVoJudgeList(); List<ExamQuestionSelectVo> judges = examVo.getExamQuestionSelectVoJudgeList();
// 初始化选择题、判断题、单选题的数量
int radioCnt = 0, checkCnt = 0, judgeCnt = 0; int radioCnt = 0, checkCnt = 0, judgeCnt = 0;
// 遍历选择题列表将选中的题目id添加到字符串中并统计选择题数量
for (ExamQuestionSelectVo radio : radios) { for (ExamQuestionSelectVo radio : radios) {
if (radio.getChecked()) { if (radio.getChecked()) {
radioIdsStr += radio.getQuestionId() + "-"; radioIdsStr += radio.getQuestionId() + "-";
radioCnt++; radioCnt++;
} }
} }
// 去除最后一个分隔符
radioIdsStr = replaceLastSeparator(radioIdsStr); radioIdsStr = replaceLastSeparator(radioIdsStr);
// 遍历判断题列表将选中的题目id添加到字符串中并统计判断题数量
for (ExamQuestionSelectVo check : checks) { for (ExamQuestionSelectVo check : checks) {
if (check.getChecked()) { if (check.getChecked()) {
checkIdsStr += check.getQuestionId() + "-"; checkIdsStr += check.getQuestionId() + "-";
checkCnt++; checkCnt++;
} }
} }
// 去除最后一个分隔符
checkIdsStr = replaceLastSeparator(checkIdsStr); checkIdsStr = replaceLastSeparator(checkIdsStr);
// 遍历单选题列表将选中的题目id添加到字符串中并统计单选题数量
for (ExamQuestionSelectVo judge : judges) { for (ExamQuestionSelectVo judge : judges) {
if (judge.getChecked()) { if (judge.getChecked()) {
judgeIdsStr += judge.getQuestionId() + "-"; judgeIdsStr += judge.getQuestionId() + "-";
judgeCnt++; judgeCnt++;
} }
} }
// 去除最后一个分隔符。
judgeIdsStr = replaceLastSeparator(judgeIdsStr); judgeIdsStr = replaceLastSeparator(judgeIdsStr);
// 设置各个题目的id。
exam.setExamQuestionIds(radioIdsStr + "-" + checkIdsStr + "-" + judgeIdsStr); exam.setExamQuestionIds(radioIdsStr + "-" + checkIdsStr + "-" + judgeIdsStr);
// 设置各个题目的id
exam.setExamQuestionIdsRadio(radioIdsStr); exam.setExamQuestionIdsRadio(radioIdsStr);
exam.setExamQuestionIdsCheck(checkIdsStr); exam.setExamQuestionIdsCheck(checkIdsStr);
exam.setExamQuestionIdsJudge(judgeIdsStr); exam.setExamQuestionIdsJudge(judgeIdsStr);
// 计算总分数 // 计算总分数
int examScore = radioCnt * exam.getExamScoreRadio() + checkCnt * exam.getExamScoreCheck() + judgeCnt * exam.getExamScoreJudge(); int examScore = radioCnt * exam.getExamScoreRadio() + checkCnt * exam.getExamScoreCheck() + judgeCnt * exam.getExamScoreJudge();
exam.setExamScore(examScore); exam.setExamScore(examScore);
// 保存exam对象。
examRepository.save(exam); examRepository.save(exam);
// 返回exam对象。
return exam; return exam;
} }
@ -499,53 +567,53 @@ public class ExamServiceImpl implements ExamService {
@Override @Override
public ExamRecord judge(String userId, String examId, HashMap<String, List<String>> answersMap) { public ExamRecord judge(String userId, String examId, HashMap<String, List<String>> answersMap) {
// 开始考试判分啦~~~ // 开始考试判分啦~~~
// 1.首先获取考试对象和选项数组 // 1.首先获取考试对象和选项数组
ExamDetailVo examDetailVo = getExamDetail(examId); ExamDetailVo examDetailVo = getExamDetail(examId);
Exam exam = examDetailVo.getExam(); Exam exam = examDetailVo.getExam();
// 2.然后获取该考试下所有的题目信息 // 2.然后获取该考试下所有的题目信息
List<String> questionIds = new ArrayList<>(); List<String> questionIds = new ArrayList<>();
// 2.1 题目id的数组 // 2.1 题目id的数组
List<String> radioIdList = Arrays.asList(examDetailVo.getRadioIds()); List<String> radioIdList = Arrays.asList(examDetailVo.getRadioIds());
List<String> checkIdList = Arrays.asList(examDetailVo.getCheckIds()); List<String> checkIdList = Arrays.asList(examDetailVo.getCheckIds());
List<String> judgeIdList = Arrays.asList(examDetailVo.getJudgeIds()); List<String> judgeIdList = Arrays.asList(examDetailVo.getJudgeIds());
questionIds.addAll(radioIdList); questionIds.addAll(radioIdList);
questionIds.addAll(checkIdList); questionIds.addAll(checkIdList);
questionIds.addAll(judgeIdList); questionIds.addAll(judgeIdList);
// 2.2 每种题目的分数 // 2.2 每种题目的分数
int radioScore = exam.getExamScoreRadio(); int radioScore = exam.getExamScoreRadio();
int checkScore = exam.getExamScoreCheck(); int checkScore = exam.getExamScoreCheck();
int judgeScore = exam.getExamScoreJudge(); int judgeScore = exam.getExamScoreJudge();
// 2.3 根据问题id的数组拿到所有的问题对象供下面步骤用 // 2.3 根据问题id的数组拿到所有的问题对象供下面步骤用
List<Question> questionList = questionRepository.findAllById(questionIds); List<Question> questionList = questionRepository.findAllById(questionIds);
Map<String, Question> questionMap = new HashMap<>(); Map<String, Question> questionMap = new HashMap<>();
for (Question question : questionList) { for (Question question : questionList) {
questionMap.put(question.getQuestionId(), question); questionMap.put(question.getQuestionId(), question);
} }
// 3.根据正确答案和用户作答信息进行判分 // 3.根据正确答案和用户作答信息进行判分
Set<String> questionIdsAnswer = answersMap.keySet(); Set<String> questionIdsAnswer = answersMap.keySet();
// 存储当前考试每个题目的得分情况 // 存储当前考试每个题目的得分情况
Map<String, Integer> judgeMap = new HashMap<>(); Map<String, Integer> judgeMap = new HashMap<>();
// 考生作答地每个题目的选项(题目和题目之间用$分隔,题目有多个选项地话用-分隔,题目和选项之间用_分隔),用于查看考试详情 // 考生作答地每个题目的选项(题目和题目之间用$分隔,题目有多个选项地话用-分隔,题目和选项之间用_分隔),用于查看考试详情
// 例子题目1的id_作答选项1-作答选项2&题目2的id_作答选项1&题目3_作答选项1-作答选项2-作答选项3 // 例子题目1的id_作答选项1-作答选项2&题目2的id_作答选项1&题目3_作答选项1-作答选项2-作答选项3
StringBuilder answerOptionIdsSb = new StringBuilder(); StringBuilder answerOptionIdsSb = new StringBuilder();
// 用户此次考试的总分 // 用户此次考试的总分
int totalScore = 0; int totalScore = 0;
for (String questionId : questionIdsAnswer) { for (String questionId : questionIdsAnswer) {
// 获取用户作答地这个题的答案信息 // 获取用户作答地这个题的答案信息
Question question = questionMap.get(questionId); Question question = questionMap.get(questionId);
// 获取答案选项 // 获取答案选项
String questionAnswerOptionIds = replaceLastSeparator(question.getQuestionAnswerOptionIds()); String questionAnswerOptionIds = replaceLastSeparator(question.getQuestionAnswerOptionIds());
List<String> questionAnswerOptionIdList = Arrays.asList(questionAnswerOptionIds.split("-")); List<String> questionAnswerOptionIdList = Arrays.asList(questionAnswerOptionIds.split("-"));
Collections.sort(questionAnswerOptionIdList); Collections.sort(questionAnswerOptionIdList);
String answerStr = listConcat(questionAnswerOptionIdList); String answerStr = listConcat(questionAnswerOptionIdList);
// 获取用户作答 // 获取用户作答
List<String> questionUserOptionIdList = answersMap.get(questionId); List<String> questionUserOptionIdList = answersMap.get(questionId);
Collections.sort(questionUserOptionIdList); Collections.sort(questionUserOptionIdList);
String userStr = listConcat(questionUserOptionIdList); String userStr = listConcat(questionUserOptionIdList);
// 判断questionAnswerOptionIds和answersMap里面的答案是否相等 // 判断questionAnswerOptionIds和answersMap里面的答案是否相等
if (answerStr.equals(userStr)) { if (answerStr.equals(userStr)) {
// 说明题目作答正确,下面根据题型给分 // 说明题目作答正确,下面根据题型给分
int score = 0; int score = 0;
if (radioIdList.contains(questionId)) { if (radioIdList.contains(questionId)) {
score = radioScore; score = radioScore;
@ -556,22 +624,22 @@ public class ExamServiceImpl implements ExamService {
if (judgeIdList.contains(questionId)) { if (judgeIdList.contains(questionId)) {
score = judgeScore; score = judgeScore;
} }
// 累计本次考试得分 // 累计本次考试得分
totalScore += score; totalScore += score;
// True代表题目答对 // True代表题目答对
answerOptionIdsSb.append(questionId + "@True_" + userStr + "$"); answerOptionIdsSb.append(questionId + "@True_" + userStr + "$");
judgeMap.put(questionId, score); judgeMap.put(questionId, score);
} else { } else {
// 说明题目作答错误,直接判零分,False代表题目答错 // 说明题目作答错误,直接判零分,False代表题目答错
answerOptionIdsSb.append(questionId + "@False_" + userStr + "$"); answerOptionIdsSb.append(questionId + "@False_" + userStr + "$");
judgeMap.put(questionId, 0); judgeMap.put(questionId, 0);
} }
} }
// 4.计算得分记录本次考试结果存到ExamRecord中 // 4.计算得分记录本次考试结果存到ExamRecord中
ExamRecord examRecord = new ExamRecord(); ExamRecord examRecord = new ExamRecord();
examRecord.setExamRecordId(IdUtil.simpleUUID()); examRecord.setExamRecordId(IdUtil.simpleUUID());
examRecord.setExamId(examId); examRecord.setExamId(examId);
// 注意去掉最后可能有的&_- // 注意去掉最后可能有的&_-
examRecord.setAnswerOptionIds(replaceLastSeparator(answerOptionIdsSb.toString())); examRecord.setAnswerOptionIds(replaceLastSeparator(answerOptionIdsSb.toString()));
examRecord.setExamJoinerId(userId); examRecord.setExamJoinerId(userId);
examRecord.setExamJoinDate(new Date()); examRecord.setExamJoinDate(new Date());
@ -582,58 +650,60 @@ public class ExamServiceImpl implements ExamService {
@Override @Override
public List<ExamRecordVo> getExamRecordList(String userId) { public List<ExamRecordVo> getExamRecordList(String userId) {
// 获取指定用户下的考试记录列表 // 获取指定用户下的考试记录列表
List<ExamRecord> examRecordList = examRecordRepository.findByExamJoinerIdOrderByExamJoinDateDesc(userId); List<ExamRecord> examRecordList = examRecordRepository.findByExamJoinerIdOrderByExamJoinDateDesc(userId);
List<ExamRecordVo> examRecordVoList = new ArrayList<>(); List<ExamRecordVo> examRecordVoList = new ArrayList<>();
for (ExamRecord examRecord : examRecordList) { for (ExamRecord examRecord : examRecordList) {
ExamRecordVo examRecordVo = new ExamRecordVo(); ExamRecordVo examRecordVo = new ExamRecordVo();
// 根据考试记录中的考试ID获取考试信息
Exam exam = examRepository.findById(examRecord.getExamId()).orElse(null); Exam exam = examRepository.findById(examRecord.getExamId()).orElse(null);
examRecordVo.setExam(exam); examRecordVo.setExam(exam);
// 根据用户ID获取用户信息
User user = userRepository.findById(userId).orElse(null); User user = userRepository.findById(userId).orElse(null);
examRecordVo.setUser(user); examRecordVo.setUser(user);
// 设置考试记录信息
examRecordVo.setExamRecord(examRecord); examRecordVo.setExamRecord(examRecord);
examRecordVoList.add(examRecordVo); examRecordVoList.add(examRecordVo);
} }
return examRecordVoList; return examRecordVoList;
} }
@Override @Override
public RecordDetailVo getRecordDetail(String recordId) { public RecordDetailVo getRecordDetail(String recordId) {
// 获取考试详情的封装对象 // 获取考试详情的封装对象
ExamRecord record = examRecordRepository.findById(recordId).orElse(null); ExamRecord record = examRecordRepository.findById(recordId).orElse(null);
RecordDetailVo recordDetailVo = new RecordDetailVo(); RecordDetailVo recordDetailVo = new RecordDetailVo();
recordDetailVo.setExamRecord(record); recordDetailVo.setExamRecord(record);
// 用户的答案,需要解析 // 用户的答案,需要解析
HashMap<String, List<String>> answersMap = new HashMap<>(); HashMap<String, List<String>> answersMap = new HashMap<>();
HashMap<String, String> resultsMap = new HashMap<>(); HashMap<String, String> resultsMap = new HashMap<>();
assert record != null; assert record != null;
String answersStr = record.getAnswerOptionIds(); String answersStr = record.getAnswerOptionIds();
// $分隔题目,因为$在正则中有特殊用途(行尾),所以需要括起来 // $分隔题目,因为$在正则中有特殊用途(行尾),所以需要括起来
String[] questionArr = answersStr.split("[$]"); String[] questionArr = answersStr.split("[$]");
for (String questionStr : questionArr) { for (String questionStr : questionArr) {
System.out.println(questionStr); System.out.println(questionStr);
// 区分开题目标题和选项 // 区分开题目标题和选项
String[] questionTitleResultAndOption = questionStr.split("_"); String[] questionTitleResultAndOption = questionStr.split("_");
String[] questionTitleAndResult = questionTitleResultAndOption[0].split("@"); String[] questionTitleAndResult = questionTitleResultAndOption[0].split("@");
String[] questionOptions = questionTitleResultAndOption[1].split("-"); String[] questionOptions = questionTitleResultAndOption[1].split("-");
// 题目:答案选项 // 题目:答案选项
answersMap.put(questionTitleAndResult[0], Arrays.asList(questionOptions)); answersMap.put(questionTitleAndResult[0], Arrays.asList(questionOptions));
// 题目True / False // 题目True / False
resultsMap.put(questionTitleAndResult[0], questionTitleAndResult[1]); resultsMap.put(questionTitleAndResult[0], questionTitleAndResult[1]);
} }
recordDetailVo.setAnswersMap(answersMap); recordDetailVo.setAnswersMap(answersMap);
recordDetailVo.setResultsMap(resultsMap); recordDetailVo.setResultsMap(resultsMap);
// 下面再计算正确答案的map // 下面再计算正确答案的map
ExamDetailVo examDetailVo = getExamDetail(record.getExamId()); ExamDetailVo examDetailVo = getExamDetail(record.getExamId());
List<String> questionIdList = new ArrayList<>(); List<String> questionIdList = new ArrayList<>();
questionIdList.addAll(Arrays.asList(examDetailVo.getRadioIds())); questionIdList.addAll(Arrays.asList(examDetailVo.getRadioIds()));
questionIdList.addAll(Arrays.asList(examDetailVo.getCheckIds())); questionIdList.addAll(Arrays.asList(examDetailVo.getCheckIds()));
questionIdList.addAll(Arrays.asList(examDetailVo.getJudgeIds())); questionIdList.addAll(Arrays.asList(examDetailVo.getJudgeIds()));
// 获取所有的问题对象 // 获取所有的问题对象
List<Question> questionList = questionRepository.findAllById(questionIdList); List<Question> questionList = questionRepository.findAllById(questionIdList);
HashMap<String, List<String>> answersRightMap = new HashMap<>(); HashMap<String, List<String>> answersRightMap = new HashMap<>();
for (Question question : questionList) { for (Question question : questionList) {
// 记得去掉最后可能出现的特殊字符 // 记得去掉最后可能出现的特殊字符
String questionAnswerOptionIdsStr = replaceLastSeparator(question.getQuestionAnswerOptionIds()); String questionAnswerOptionIdsStr = replaceLastSeparator(question.getQuestionAnswerOptionIds());
String[] questionAnswerOptionIds = questionAnswerOptionIdsStr.split("-"); String[] questionAnswerOptionIds = questionAnswerOptionIdsStr.split("-");
answersRightMap.put(question.getQuestionId(), Arrays.asList(questionAnswerOptionIds)); answersRightMap.put(question.getQuestionId(), Arrays.asList(questionAnswerOptionIds));
@ -641,7 +711,6 @@ public class ExamServiceImpl implements ExamService {
recordDetailVo.setAnswersRightMap(answersRightMap); recordDetailVo.setAnswersRightMap(answersRightMap);
return recordDetailVo; return recordDetailVo;
} }
/** /**
* - * -
* *
@ -650,7 +719,7 @@ public class ExamServiceImpl implements ExamService {
*/ */
private String replaceLastSeparator(String str) { private String replaceLastSeparator(String str) {
String lastChar = str.substring(str.length() - 1); String lastChar = str.substring(str.length() - 1);
// 题目和题目之间用$分隔,题目有多个选项地话用-分隔,题目和选项之间用_分隔 // 题目和题目之间用$分隔,题目有多个选项地话用-分隔,题目和选项之间用_分隔
if ("-".equals(lastChar) || "_".equals(lastChar) || "$".equals(lastChar)) { if ("-".equals(lastChar) || "_".equals(lastChar) || "$".equals(lastChar)) {
str = StrUtil.sub(str, 0, str.length() - 1); str = StrUtil.sub(str, 0, str.length() - 1);
} }

@ -47,7 +47,12 @@ public class UserServiceImpl implements UserService {
@Autowired @Autowired
ActionRepository actionRepository; ActionRepository actionRepository;
/**
*
*
* @param registerDTO
* @return null
*/
@Override @Override
public User register(RegisterDTO registerDTO) { public User register(RegisterDTO registerDTO) {
try { try {
@ -81,6 +86,12 @@ public class UserServiceImpl implements UserService {
} }
} }
/**
*
*
* @param loginQo
* @return tokennull
*/
@Override @Override
public String login(LoginQo loginQo) { public String login(LoginQo loginQo) {
User user; User user;
@ -106,7 +117,12 @@ public class UserServiceImpl implements UserService {
} }
return null; return null;
} }
/**
*
*
* @param userId id
* @return
*/
@Override @Override
public UserVo getUserInfo(String userId) { public UserVo getUserInfo(String userId) {
User user = userRepository.findById(userId).orElse(null); User user = userRepository.findById(userId).orElse(null);
@ -115,7 +131,12 @@ public class UserServiceImpl implements UserService {
BeanUtils.copyProperties(user, userVo); BeanUtils.copyProperties(user, userVo);
return userVo; return userVo;
} }
/**
*
*
* @param userId id
* @return
*/
@Override @Override
public UserInfoVo getInfo(String userId) { public UserInfoVo getInfo(String userId) {
User user = userRepository.findById(userId).orElse(null); User user = userRepository.findById(userId).orElse(null);

@ -7,22 +7,32 @@
package lsgwr.exam.utils; package lsgwr.exam.utils;
import lsgwr.exam.vo.ResultVO; import lsgwr.exam.vo.ResultVO;
/**
*
*/
public class ResultVOUtil { public class ResultVOUtil {
/**
*
*/
public static ResultVO success(Integer code, String msg, Object object) { public static ResultVO success(Integer code, String msg, Object object) {
return new ResultVO(code, msg, object); return new ResultVO(code, msg, object);
} }
/**
*
*/
public static ResultVO success(Object object) { public static ResultVO success(Object object) {
return new ResultVO(0, "成功", object); return new ResultVO(0, "成功", object);
} }
/**
*
*/
public static ResultVO success() { public static ResultVO success() {
return new ResultVO(0, "成功", null); return new ResultVO(0, "成功", null);
} }
/**
*
*/
public static ResultVO error(Integer code, String msg) { public static ResultVO error(Integer code, String msg) {
return new ResultVO(code, msg, null); return new ResultVO(code, msg, null);
} }

@ -8,15 +8,24 @@ package lsgwr.exam.vo;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data; import lombok.Data;
/**
* Action
*/
@Data @Data
public class ActionVo { public class ActionVo {
/**
*
*/
@JsonProperty("action") @JsonProperty("action")
private String actionName; private String actionName;
/**
*
*/
@JsonProperty("describe") @JsonProperty("describe")
private String actionDescription; private String actionDescription;
/**
*
*/
@JsonProperty("defaultCheck") @JsonProperty("defaultCheck")
private Boolean defaultCheck; private Boolean defaultCheck;
} }

@ -1,3 +1,9 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019-06-23 19:30
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.vo; package lsgwr.exam.vo;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
@ -10,9 +16,6 @@ import lombok.Data;
*/ */
@Data @Data
public class ExamCardVo { public class ExamCardVo {
/**
* ID
*/
@JsonProperty("id") @JsonProperty("id")
private String examId; private String examId;
/** /**
@ -34,10 +37,10 @@ public class ExamCardVo {
* *
*/ */
@JsonProperty("score") @JsonProperty("score")
private Integer examScore; private Integer examScore;// 考试的分数
/** /**
* *
*/ */
@JsonProperty("elapse") @JsonProperty("elapse")
private Integer examTimeLimit; private Integer examTimeLimit;// 考试的时间限制,以分钟为单位
} }

@ -5,60 +5,63 @@
* @email : liangshanguang2@gmail.com * @email : liangshanguang2@gmail.com
***********************************************************/ ***********************************************************/
package lsgwr.exam.vo; package lsgwr.exam.vo;
// 引入Jackson库中的注解用于JSON序列化和反序列化时自定义属性名
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
// 引入Lombok库中的@Data注解它会自动为你的类的字段生成getter和setter方法以及toString、equals和hashCode方法
import lombok.Data; import lombok.Data;
import java.util.List; import java.util.List;
// 使用@Data注解来自动生成getter、setter等方法
@Data @Data
public class ExamCreateVo { public class ExamCreateVo {
// 考试名称,通过@JsonProperty注解指定JSON字段名为"name"
@JsonProperty("name") @JsonProperty("name")
private String examName; private String examName;
// 考试头像或图标,通过@JsonProperty注解指定JSON字段名为"avatar"
@JsonProperty("avatar") @JsonProperty("avatar")
private String examAvatar; private String examAvatar;
// 考试描述,通过@JsonProperty注解指定JSON字段名为"desc"
@JsonProperty("desc") @JsonProperty("desc")
private String examDescription; private String examDescription;
/** /**
* * @JsonPropertyJSON"elapse"
*
*/ */
@JsonProperty("elapse") @JsonProperty("elapse")
private Integer examTimeLimit; private Integer examTimeLimit;
/** /**
* * 使List<ExamQuestionSelectVo>
* ExamQuestionSelectVoVO
*/ */
private List<ExamQuestionSelectVo> radios; private List<ExamQuestionSelectVo> radios;
/** /**
* * 使List<ExamQuestionSelectVo>
*/ */
private List<ExamQuestionSelectVo> checks; private List<ExamQuestionSelectVo> checks;
/** /**
* * 使List<ExamQuestionSelectVo>
*/ */
private List<ExamQuestionSelectVo> judges; private List<ExamQuestionSelectVo> judges;
/** /**
* * @JsonPropertyJSON"radioScore"
*/ */
@JsonProperty("radioScore") @JsonProperty("radioScore")
private Integer examScoreRadio; private Integer examScoreRadio;
/** /**
* * @JsonPropertyJSON"checkScore"
*/ */
@JsonProperty("checkScore") @JsonProperty("checkScore")
private Integer examScoreCheck; private Integer examScoreCheck;
/** /**
* * @JsonPropertyJSON"judgeScore"
*/ */
@JsonProperty("judgeScore") @JsonProperty("judgeScore")
private Integer examScoreJudge; private Integer examScoreJudge;

@ -5,29 +5,42 @@
* @email : liangshanguang2@gmail.com * @email : liangshanguang2@gmail.com
***********************************************************/ ***********************************************************/
package lsgwr.exam.vo; package lsgwr.exam.vo;
// 引入Exam实体类它可能包含了考试的详细信息如考试ID、名称、描述等
import lsgwr.exam.entity.Exam; import lsgwr.exam.entity.Exam;
// 引入Lombok库的@Data注解用于自动生成getter、setter等方法
import lombok.Data; import lombok.Data;
// 使用@Data注解来自动生成这个类的getter、setter等方法
@Data @Data
public class ExamDetailVo { public class ExamDetailVo {
/** /**
* *
* Exam
* ID
* ExamDetailVoExam
*/ */
private Exam exam; private Exam exam;
/** /**
* id * id
* ID
*
* ID
*/ */
private String[] radioIds; private String[] radioIds;
/** /**
* id * id
* idID
*
*
*/ */
private String[] checkIds; private String[] checkIds;
/** /**
* id * id
* ID
*
* ID
*/ */
private String[] judgeIds; private String[] judgeIds;

@ -4,37 +4,40 @@
* @date : 2019-06-22 17:00 * @date : 2019-06-22 17:00
* @email : liangshanguang2@gmail.com * @email : liangshanguang2@gmail.com
***********************************************************/ ***********************************************************/
package lsgwr.exam.vo; package lsgwr.exam.vo;// 定义包名,用于组织类文件,避免命名冲突
// 导入Jackson库的JsonProperty注解用于JSON序列化时自定义字段名
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
// 导入Lombok库的Data注解用于自动生成getter、setter、equals、hashCode和toString方法
import lombok.Data; import lombok.Data;
// 导入Java的List接口用于存储ExamVo对象的集合
import java.util.List; import java.util.List;
// 使用Lombok的@Data注解自动为该类生成getter、setter等方法
@Data @Data
public class ExamPageVo { public class ExamPageVo {
/** /**
* *
*/ */
private Integer pageSize; private Integer pageSize;
/** /**
* 1 * 110
* 1
*/ */
private Integer pageNo; private Integer pageNo;
/** /**
* *
*/ */
private Long totalCount; private Long totalCount;
/** /**
* *
*/ */
private Integer totalPage; private Integer totalPage;
/** /**
* * ExamVoExamVo
* @JsonProperty("data")JSONexamVoListJSON"data"
*/ */
@JsonProperty("data") @JsonProperty("data")
private List<ExamVo> examVoList; private List<ExamVo> examVoList;

@ -4,22 +4,32 @@
* @date : 2019-06-17 23:10 * @date : 2019-06-17 23:10
* @email : liangshanguang2@gmail.com * @email : liangshanguang2@gmail.com
***********************************************************/ ***********************************************************/
package lsgwr.exam.vo; package lsgwr.exam.vo;// 定义包名,用于组织类文件,避免命名冲突
// 导入Jackson库的JsonProperty注解用于JSON序列化时自定义字段名
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
// 导入Lombok库的Data注解用于自动生成getter、setter、equals、hashCode和toString方法
import lombok.Data; import lombok.Data;
// 使用Lombok的@Data注解自动为该类生成getter、setter等方法
@Data @Data
public class ExamQuestionSelectVo { public class ExamQuestionSelectVo {
/**
* JSON"id"
*
*/
@JsonProperty("id") @JsonProperty("id")
private String questionId; private String questionId;
/**
* JSON"name"
*
*/
@JsonProperty("name") @JsonProperty("name")
private String questionName; private String questionName;
/** /**
* .falsetrue * false
* * true
*
* JSON"checked"
*/ */
@JsonProperty("checked") @JsonProperty("checked")
private Boolean checked = false; private Boolean checked = false;

@ -4,21 +4,35 @@
* @date : 2019-06-23 11:00 * @date : 2019-06-23 11:00
* @email : liangshanguang2@gmail.com * @email : liangshanguang2@gmail.com
***********************************************************/ ***********************************************************/
package lsgwr.exam.vo; package lsgwr.exam.vo;// 定义包名,用于组织类文件,避免命名冲突
// 导入Jackson库的JsonProperty注解用于JSON序列化时自定义字段名
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
// 导入Lombok库的Data注解用于自动生成getter、setter、equals、hashCode和toString方法
import lombok.Data; import lombok.Data;
// 导入Java的List接口用于存储对象的集合
import java.util.List; import java.util.List;
// 使用Lombok的@Data注解自动为该类生成getter、setter等方法
@Data @Data
public class ExamQuestionTypeVo { public class ExamQuestionTypeVo {
/**
* ExamQuestionSelectVo
* JSON"radios"
* "radios"radio buttons
*/
@JsonProperty("radios") @JsonProperty("radios")
private List<ExamQuestionSelectVo> examQuestionSelectVoRadioList; private List<ExamQuestionSelectVo> examQuestionSelectVoRadioList;
/**
* ExamQuestionSelectVo
* JSON"checks"
* "checks"checkboxes
*/
@JsonProperty("checks") @JsonProperty("checks")
private List<ExamQuestionSelectVo> examQuestionSelectVoCheckList; private List<ExamQuestionSelectVo> examQuestionSelectVoCheckList;
/**
* ExamQuestionSelectVo
* JSON"judges"
* "judges"true/falseyes/no
*/
@JsonProperty("judges") @JsonProperty("judges")
private List<ExamQuestionSelectVo> examQuestionSelectVoJudgeList; private List<ExamQuestionSelectVo> examQuestionSelectVoJudgeList;
} }

@ -4,27 +4,34 @@
* @date : 2019/10/25 7:42 * @date : 2019/10/25 7:42
* @email : liangshanguang2@gmail.com * @email : liangshanguang2@gmail.com
***********************************************************/ ***********************************************************/
package lsgwr.exam.vo; package lsgwr.exam.vo;// 定义包名,用于组织类文件,避免命名冲突
// 导入相关的实体类
import lsgwr.exam.entity.Exam; import lsgwr.exam.entity.Exam;// 考试实体类
import lsgwr.exam.entity.ExamRecord; import lsgwr.exam.entity.ExamRecord; // 考试记录实体类
import lsgwr.exam.entity.User; import lsgwr.exam.entity.User;// 用户实体类
// 导入Lombok库的Data注解用于自动生成getter、setter、equals、hashCode和toString方法
import lombok.Data; import lombok.Data;
// 使用Lombok的@Data注解自动生成getter、setter等方法
@Data @Data
public class ExamRecordVo { public class ExamRecordVo {
/** /**
* *
*
* ExamExam
*/ */
private Exam exam; private Exam exam;
/** /**
* *
*
* ExamRecordExamRecord
*/ */
private ExamRecord examRecord; private ExamRecord examRecord;
/** /**
* *
*
* UserUser
*/ */
private User user; private User user;
} }

@ -4,86 +4,83 @@
* @date : 2019/5/14 07:42 * @date : 2019/5/14 07:42
* @email : liangshanguang2@gmail.com * @email : liangshanguang2@gmail.com
***********************************************************/ ***********************************************************/
// 定义包名,用于组织类文件并避免命名冲突
package lsgwr.exam.vo; package lsgwr.exam.vo;
// 导入所需的库和注解
import com.fasterxml.jackson.annotation.JsonFormat;// 用于日期格式的序列化和反序列化
import com.fasterxml.jackson.annotation.JsonProperty;// 用于自定义JSON字段名
import lombok.Data;// 用于自动生成getter、setter等方法
import com.fasterxml.jackson.annotation.JsonFormat; import java.util.Date;// Java日期类
import com.fasterxml.jackson.annotation.JsonProperty; import java.util.List;// Java列表接口
import lombok.Data; // 使用Lombok的@Data注解自动生成getter、setter等方法
import java.util.Date;
import java.util.List;
@Data @Data
public class ExamVo { public class ExamVo {
// 使用@JsonProperty注解自定义JSON字段名为"id"
@JsonProperty("id") @JsonProperty("id")
private String examId; private String examId;// 考试的唯一标识符
// 使用@JsonProperty注解自定义JSON字段名为"name"
@JsonProperty("name") @JsonProperty("name")
private String examName; private String examName;// 考试名称
// 使用@JsonProperty注解自定义JSON字段名为"avatar"
@JsonProperty("avatar") @JsonProperty("avatar")
private String examAvatar; private String examAvatar;// 考试图标或头像
// 使用@JsonProperty注解自定义JSON字段名为"desc"
@JsonProperty("desc") @JsonProperty("desc")
private String examDescription; private String examDescription;// 考试描述
// 单选题列表JSON字段名为"radios"
@JsonProperty("radios") @JsonProperty("radios")
private List<ExamQuestionSelectVo> examQuestionSelectVoRadioList; private List<ExamQuestionSelectVo> examQuestionSelectVoRadioList;// 单选题选项列表
// 多选题列表JSON字段名为"checks"
@JsonProperty("checks") @JsonProperty("checks")
private List<ExamQuestionSelectVo> examQuestionSelectVoCheckList; private List<ExamQuestionSelectVo> examQuestionSelectVoCheckList;// 多选题选项列表
// 判断题列表JSON字段名为"judges"
@JsonProperty("judges") @JsonProperty("judges")
private List<ExamQuestionSelectVo> examQuestionSelectVoJudgeList; private List<ExamQuestionSelectVo> examQuestionSelectVoJudgeList;// 判断题选项列表
// 考试总分JSON字段名为"score"
@JsonProperty("score") @JsonProperty("score")
private Integer examScore; private Integer examScore;// 考试的总分数
// 单选题总分JSON字段名为"radioScore"
@JsonProperty("radioScore") @JsonProperty("radioScore")
private Integer examScoreRadio; private Integer examScoreRadio;// 单选题的总分数
// 多选题总分JSON字段名为"checkScore"
@JsonProperty("checkScore") @JsonProperty("checkScore")
private Integer examScoreCheck; private Integer examScoreCheck;// 多选题的总分数
// 判断题总分JSON字段名为"judgeScore"
@JsonProperty("judgeScore") @JsonProperty("judgeScore")
private Integer examScoreJudge; private Integer examScoreJudge;// 判断题的总分数
/** // 考试创建人的名称JSON字段名为"creator"
* id // 注意这里假设只存储了创建人的名称实际可能需要根据ID查询数据库获取
*/
@JsonProperty("creator") @JsonProperty("creator")
private String examCreator; private String examCreator;// 考试的创建者名称
/** // 考试的时间限制分钟JSON字段名为"elapse"
*
*/
@JsonProperty("elapse") @JsonProperty("elapse")
private Integer examTimeLimit; private Integer examTimeLimit;// 考试的时间限制,单位为分钟
/** // 考试开始时间JSON字段名为"startDate"
* // 使用@JsonFormat注解指定日期格式和时区
*/
@JsonProperty("startDate") @JsonProperty("startDate")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date examStartDate; private Date examStartDate;// 考试的开始时间
/** // 考试结束时间JSON字段名为"endDate"
* // 使用@JsonFormat注解指定日期格式和时区
*/
@JsonProperty("endDate") @JsonProperty("endDate")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date examEndDate; private Date examEndDate;// 考试的结束时间
/** // 创建时间JSON字段名为"createTime"
* // 使用@JsonFormat注解指定日期格式和时区
*/
@JsonProperty("createTime") @JsonProperty("createTime")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime; private Date createTime;// 记录的创建时间
/** // 更新时间JSON字段名为"updateTime"
* // 使用@JsonFormat注解指定日期格式和时区
*/
@JsonProperty("updateTime") @JsonProperty("updateTime")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date updateTime; private Date updateTime;// 记录的更新时间
} }

@ -16,7 +16,9 @@ import java.io.Serializable;
@AllArgsConstructor @AllArgsConstructor
@NoArgsConstructor @NoArgsConstructor
public class JsonData implements Serializable { public class JsonData implements Serializable {
/**
* id
*/
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**

@ -10,15 +10,24 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data; import lombok.Data;
import java.util.List; import java.util.List;
/**
*
*/
@Data @Data
public class PageVo { public class PageVo {
/**
*
*/
@JsonProperty("actionEntitySet") @JsonProperty("actionEntitySet")
private List<ActionVo> actionVoList; private List<ActionVo> actionVoList;
/**
*
*/
@JsonProperty("permissionId") @JsonProperty("permissionId")
private String pageName; private String pageName;
/**
*
*/
@JsonProperty("permissionName") @JsonProperty("permissionName")
private String pageDescription; private String pageDescription;
} }

@ -10,7 +10,9 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data; import lombok.Data;
import java.util.List; import java.util.List;
/**
* ,
*/
@Data @Data
public class QuestionCreateSimplifyVo { public class QuestionCreateSimplifyVo {
/** /**

@ -10,7 +10,9 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data; import lombok.Data;
import java.util.List; import java.util.List;
/**
*
*/
@Data @Data
public class QuestionCreateVo { public class QuestionCreateVo {
/** /**

@ -11,7 +11,9 @@ import lombok.Data;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
/**
*
*/
@Data @Data
public class QuestionDetailVo { public class QuestionDetailVo {
/** /**

@ -8,7 +8,9 @@ package lsgwr.exam.vo;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data; import lombok.Data;
/**
*
*/
@Data @Data
public class QuestionOptionCreateVo { public class QuestionOptionCreateVo {

@ -8,18 +8,29 @@ package lsgwr.exam.vo;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data; import lombok.Data;
/**
*
*/
@Data @Data
public class QuestionOptionVo { public class QuestionOptionVo {
/**
* id
*/
@JsonProperty("id") @JsonProperty("id")
private String questionOptionId; private String questionOptionId;
/**
*
*/
@JsonProperty("content") @JsonProperty("content")
private String questionOptionContent; private String questionOptionContent;
/**
*
*/
@JsonProperty("answer") @JsonProperty("answer")
private Boolean answer = false; private Boolean answer = false;
/**
*
*/
@JsonProperty("description") @JsonProperty("description")
private String questionOptionDescription; private String questionOptionDescription;
} }

@ -10,7 +10,9 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data; import lombok.Data;
import java.util.List; import java.util.List;
/**
*
*/
@Data @Data
public class QuestionPageVo { public class QuestionPageVo {

@ -13,15 +13,24 @@ import lsgwr.exam.entity.QuestionType;
import lombok.Data; import lombok.Data;
import java.util.List; import java.util.List;
/**
*
*/
@Data @Data
public class QuestionSelectionVo { public class QuestionSelectionVo {
/**
*
*/
@JsonProperty("types") @JsonProperty("types")
private List<QuestionType> questionTypeList; private List<QuestionType> questionTypeList;
/**
*
*/
@JsonProperty("categories") @JsonProperty("categories")
private List<QuestionCategory> questionCategoryList; private List<QuestionCategory> questionCategoryList;
/**
*
*/
@JsonProperty("levels") @JsonProperty("levels")
private List<QuestionLevel> questionLevelList; private List<QuestionLevel> questionLevelList;
} }

@ -12,15 +12,24 @@ import lombok.Data;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
/**
* VO
*/
@Data @Data
public class QuestionVo { public class QuestionVo {
/**
* idquestion
*/
@JsonProperty("id") @JsonProperty("id")
private String questionId; private String questionId;
/**
* question
*/
@JsonProperty("name") @JsonProperty("name")
private String questionName; private String questionName;
/**
* question
*/
@JsonProperty("score") @JsonProperty("score")
private Integer questionScore; private Integer questionScore;

@ -11,7 +11,9 @@ import lombok.Data;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
/**
* VO
*/
@Data @Data
public class RecordDetailVo { public class RecordDetailVo {
/** /**

@ -13,7 +13,12 @@ import lombok.Data;
@JsonInclude(JsonInclude.Include.NON_NULL) // 避免返回NULL的字段 @JsonInclude(JsonInclude.Include.NON_NULL) // 避免返回NULL的字段
public class ResultVO<T> { public class ResultVO<T> {
/**
*
* @param code
* @param msg
* @param data
*/
public ResultVO(Integer code, String msg, T data) { public ResultVO(Integer code, String msg, T data) {
this.code = code; this.code = code;
this.msg = msg; this.msg = msg;

@ -10,18 +10,29 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data; import lombok.Data;
import java.util.List; import java.util.List;
/**
* VO
*/
@Data @Data
public class RoleVo { public class RoleVo {
/**
*
*/
@JsonProperty("id") @JsonProperty("id")
private String roleName; private String roleName;
/**
*
*/
@JsonProperty("name") @JsonProperty("name")
private String roleDescription; private String roleDescription;
/**
*
*/
@JsonProperty("describe") @JsonProperty("describe")
private String roleDetail; private String roleDetail;
/**
*
*/
@JsonProperty("permissions") @JsonProperty("permissions")
private List<PageVo> pageVoList; private List<PageVo> pageVoList;
} }

@ -8,19 +8,29 @@ package lsgwr.exam.vo;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data; import lombok.Data;
/**
*
*/
@Data @Data
public class UserInfoVo { public class UserInfoVo {
/**
* ID
*/
@JsonProperty("id") @JsonProperty("id")
private String userId; private String userId;
/**
* URL
*/
@JsonProperty("avatar") @JsonProperty("avatar")
private String userAvatar; private String userAvatar;
/**
*
*/
@JsonProperty("name") @JsonProperty("name")
private String userNickname; private String userNickname;
/**
*
*/
@JsonProperty("username") @JsonProperty("username")
private String userUsername; private String userUsername;

@ -8,30 +8,49 @@ package lsgwr.exam.vo;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data; import lombok.Data;
/**
*
*/
@Data @Data
public class UserVo { public class UserVo {
/**
* ID
*/
@JsonProperty("id") @JsonProperty("id")
private String userId; private String userId;
/**
*
*/
@JsonProperty("username") @JsonProperty("username")
private String userUsername; private String userUsername;
/**
*
*/
@JsonProperty("nickname") @JsonProperty("nickname")
private String userNickname; private String userNickname;
/**
* ID
*/
@JsonProperty("role") @JsonProperty("role")
private Integer userRoleId; private Integer userRoleId;
/**
*
*/
@JsonProperty("avatar") @JsonProperty("avatar")
private String userAvatar; private String userAvatar;
/**
*
*/
@JsonProperty("description") @JsonProperty("description")
private String userDescription; private String userDescription;
/**
*
*/
@JsonProperty("email") @JsonProperty("email")
private String userEmail; private String userEmail;
/**
*
*/
@JsonProperty("phone") @JsonProperty("phone")
private String userPhone; private String userPhone;
} }

@ -5,7 +5,7 @@ spring:
driver-class-name: com.mysql.cj.jdbc.Driver driver-class-name: com.mysql.cj.jdbc.Driver
username: root username: root
password: aA111111 password: aA111111
url: jdbc:mysql://localhost:3306/exam?characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai url: jdbc:mysql://localhost:3306/exam?characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&&allowPublicKeyRetrieval=true
jpa: jpa:
# 调试的时候用用于打印完成SQL语句(但是不打印参数),联合下面的logging.level一同打印最完整的SQL信息(语句+参数) # 调试的时候用用于打印完成SQL语句(但是不打印参数),联合下面的logging.level一同打印最完整的SQL信息(语句+参数)
show-sql: false show-sql: false

File diff suppressed because one or more lines are too long

@ -6,13 +6,91 @@
<meta name="viewport" content="width=device-width,initial-scale=1.0"> <meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>logo.png"> <link rel="icon" href="<%= BASE_URL %>logo.png">
<title>在线考试系统</title> <title>在线考试系统</title>
<style>#loading-mask{position:fixed;left:0;top:0;height:100%;width:100%;background:#fff;user-select:none;z-index:9999;overflow:hidden}.loading-wrapper{position:absolute;top:50%;left:50%;transform:translate(-50%,-100%)}.loading-dot{animation:antRotate 1.2s infinite linear;transform:rotate(45deg);position:relative;display:inline-block;font-size:64px;width:64px;height:64px;box-sizing:border-box}.loading-dot i{width:22px;height:22px;position:absolute;display:block;background-color:#1890ff;border-radius:100%;transform:scale(.75);transform-origin:50% 50%;opacity:.3;animation:antSpinMove 1s infinite linear alternate}.loading-dot i:nth-child(1){top:0;left:0}.loading-dot i:nth-child(2){top:0;right:0;-webkit-animation-delay:.4s;animation-delay:.4s}.loading-dot i:nth-child(3){right:0;bottom:0;-webkit-animation-delay:.8s;animation-delay:.8s}.loading-dot i:nth-child(4){bottom:0;left:0;-webkit-animation-delay:1.2s;animation-delay:1.2s}@keyframes antRotate{to{-webkit-transform:rotate(405deg);transform:rotate(405deg)}}@-webkit-keyframes antRotate{to{-webkit-transform:rotate(405deg);transform:rotate(405deg)}}@keyframes antSpinMove{to{opacity:1}}@-webkit-keyframes antSpinMove{to{opacity:1}}</style> <!-- 定义加载中的样式 -->
<style>#loading-mask{
position:fixed;left:0;top:0;height:100%;
width:100%;background:#fff;user-select:none;
z-index:9999;overflow:hidden}
.loading-wrapper{
position:absolute;
top:50%;
left:50%;
transform:translate(-50%,-100%)
}
.loading-dot{
animation:antRotate 1.2s infinite linear;
transform:rotate(45deg);
position:relative;
display:inline-block;
font-size:64px;
width:64px;
height:64px;
box-sizing:border-box}
.loading-dot i{
width:22px;
height:22px;
position:absolute;
display:block;
background-color:#1890ff;
border-radius:100%;
transform:scale(.75);
transform-origin:50% 50%;
opacity:.3;
animation:antSpinMove 1s infinite linear alternate
}
.loading-dot i:nth-child(1){
top:0;
left:0
}
.loading-dot i:nth-child(2){
top:0;
right:0;
-webkit-animation-delay:.4s;
animation-delay:.4s
}
.loading-dot i:nth-child(3){
right:0;
bottom:0;
-webkit-animation-delay:.8s;
animation-delay:.8s
}
.loading-dot i:nth-child(4){
bottom:0;
left:0;
-webkit-animation-delay:1.2s;
animation-delay:1.2s
}
@keyframes antRotate{
to{
-webkit-transform:rotate(405deg);
transform:rotate(405deg)
}
}
@-webkit-keyframes antRotate{to{
-webkit-transform:rotate(405deg);
transform:rotate(405deg)
}
}
@keyframes antSpinMove{
to{
opacity:1
}
}
@-webkit-keyframes antSpinMove{
to{
opacity:1
}
}
</style>
</head> </head>
<body> <body>
<!-- 当JavaScript被禁用时显示提示信息 -->
<noscript> <noscript>
<strong>We're sorry but vue-antd-pro doesn't work properly without JavaScript enabled. Please enable it to continue.</strong> <strong>We're sorry but vue-antd-pro doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript> </noscript>
<!-- 应用的主容器 -->
<div id="app"> <div id="app">
<!-- 加载中的遮罩层 -->
<div id="loading-mask"> <div id="loading-mask">
<div class="loading-wrapper"> <div class="loading-wrapper">
<span class="loading-dot loading-dot-spin"><i></i><i></i><i></i><i></i></span> <span class="loading-dot loading-dot-spin"><i></i><i></i><i></i><i></i></span>

@ -1 +1,52 @@
#preloadingAnimation{position:fixed;left:0;top:0;height:100%;width:100%;background:#ffffff;user-select:none;z-index: 9999;overflow: hidden}.lds-roller{display:inline-block;position:relative;left:50%;top:50%;transform:translate(-50%,-50%);width:64px;height:64px;}.lds-roller div{animation:lds-roller 1.2s cubic-bezier(0.5,0,0.5,1) infinite;transform-origin:32px 32px;}.lds-roller div:after{content:" ";display:block;position:absolute;width:6px;height:6px;border-radius:50%;background:#13c2c2;margin:-3px 0 0 -3px;}.lds-roller div:nth-child(1){animation-delay:-0.036s;}.lds-roller div:nth-child(1):after{top:50px;left:50px;}.lds-roller div:nth-child(2){animation-delay:-0.072s;}.lds-roller div:nth-child(2):after{top:54px;left:45px;}.lds-roller div:nth-child(3){animation-delay:-0.108s;}.lds-roller div:nth-child(3):after{top:57px;left:39px;}.lds-roller div:nth-child(4){animation-delay:-0.144s;}.lds-roller div:nth-child(4):after{top:58px;left:32px;}.lds-roller div:nth-child(5){animation-delay:-0.18s;}.lds-roller div:nth-child(5):after{top:57px;left:25px;}.lds-roller div:nth-child(6){animation-delay:-0.216s;}.lds-roller div:nth-child(6):after{top:54px;left:19px;}.lds-roller div:nth-child(7){animation-delay:-0.252s;}.lds-roller div:nth-child(7):after{top:50px;left:14px;}.lds-roller div:nth-child(8){animation-delay:-0.288s;}.lds-roller div:nth-child(8):after{top:45px;left:10px;}#preloadingAnimation .load-tips{color: #13c2c2;font-size:2rem;position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);margin-top:80px;text-align:center;width:400px;height:64px;} @keyframes lds-roller{0%{transform:rotate(0deg);} 100%{transform:rotate(360deg);}} #preloadingAnimation{
position:fixed;left:0;top:0;height:100%;width:100%;background:#ffffff;user-select:none;
z-index: 9999;overflow: hidden}
.lds-roller{
display:inline-block;
position:relative;
left:50%;
top:50%;
transform:translate(-50%,-50%);
width:64px;
height:64px;
}
.lds-roller div{
animation:lds-roller 1.2s cubic-bezier(0.5,0,0.5,1) infinite;
transform-origin:32px 32px;
}
.lds-roller div:after{
content:" ";
display:block;
position:absolute;
width:6px;
height:6px;
border-radius:50%;
background:#13c2c2;
margin:-3px 0 0 -3px;
}
.lds-roller div:nth-child(1){animation-delay:-0.036s;}
.lds-roller div:nth-child(1):after{top:50px;left:50px;}
.lds-roller div:nth-child(2){animation-delay:-0.072s;}
.lds-roller div:nth-child(2):after{top:54px;left:45px;}
.lds-roller div:nth-child(3){animation-delay:-0.108s;}
.lds-roller div:nth-child(3):after{top:57px;left:39px;}
.lds-roller div:nth-child(4){animation-delay:-0.144s;}
.lds-roller div:nth-child(4):after{top:58px;left:32px;}
.lds-roller div:nth-child(5){animation-delay:-0.18s;}
.lds-roller div:nth-child(5):after{top:57px;left:25px;}
.lds-roller div:nth-child(6){animation-delay:-0.216s;}
.lds-roller div:nth-child(6):after{top:54px;left:19px;}
.lds-roller div:nth-child(7){animation-delay:-0.252s;}
.lds-roller div:nth-child(7):after{top:50px;left:14px;}
.lds-roller div:nth-child(8){animation-delay:-0.288s;}
.lds-roller div:nth-child(8):after{top:45px;left:10px;}
#preloadingAnimation .load-tips{
color: #13c2c2;
font-size:2rem;
position:absolute;
left:50%;
top:50%;
transform:translate(-50%,-50%);margin-top:80px;
text-align:center;width:400px;height:64px;}
@keyframes lds-roller{0%{transform:rotate(0deg);}
100%{transform:rotate(360deg);}}

@ -1 +1,27 @@
<div id="preloadingAnimation"><div class=lds-roller><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div></div><div class=load-tips>Loading</div></div> <div id="preloadingAnimation"><div class=lds-roller><div>
</div>
<div>
</div>
<div>
</div>
<div>
</div>
<div>
</div>
<div>
</div>
<div>
</div>
<div>
</div>
</div>
<div class=load-tips>Loading</div>
</div>

@ -1,5 +1,31 @@
/**
* 预加载动画
*/
<div class="preloading-animate"> <div class="preloading-animate">
<!--预加载的包装容器 -->
<div class="preloading-wrapper"> <div class="preloading-wrapper">
<svg class="preloading-balls" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid"><circle cx="67.802" cy="59.907" r="6" fill="#51CACC"><animate attributeName="cx" values="75;57.72542485937369" keyTimes="0;1" dur="1s" repeatCount="indefinite"/><animate attributeName="cy" values="50;73.77641290737884" keyTimes="0;1" dur="1s" repeatCount="indefinite"/><animate attributeName="fill" values="#51CACC;#9DF871" keyTimes="0;1" dur="1s" repeatCount="indefinite"/></circle><circle cx="46.079" cy="69.992" r="6" fill="#9DF871"><animate attributeName="cx" values="57.72542485937369;29.774575140626318" keyTimes="0;1" dur="1s" repeatCount="indefinite"/><animate attributeName="cy" values="73.77641290737884;64.69463130731182" keyTimes="0;1" dur="1s" repeatCount="indefinite"/><animate attributeName="fill" values="#9DF871;#E0FF77" keyTimes="0;1" dur="1s" repeatCount="indefinite"/></circle><circle cx="29.775" cy="52.449" r="6" fill="#E0FF77"><animate attributeName="cx" values="29.774575140626318;29.774575140626315" keyTimes="0;1" dur="1s" repeatCount="indefinite"/><animate attributeName="cy" values="64.69463130731182;35.30536869268818" keyTimes="0;1" dur="1s" repeatCount="indefinite"/><animate attributeName="fill" values="#E0FF77;#DE9DD6" keyTimes="0;1" dur="1s" repeatCount="indefinite"/></circle><circle cx="41.421" cy="31.521" r="6" fill="#DE9DD6"><animate attributeName="cx" values="29.774575140626315;57.72542485937368" keyTimes="0;1" dur="1s" repeatCount="indefinite"/><animate attributeName="cy" values="35.30536869268818;26.22358709262116" keyTimes="0;1" dur="1s" repeatCount="indefinite"/><animate attributeName="fill" values="#DE9DD6;#FF708E" keyTimes="0;1" dur="1s" repeatCount="indefinite"/></circle><circle cx="64.923" cy="36.13" r="6" fill="#FF708E"><animate attributeName="cx" values="57.72542485937368;75" keyTimes="0;1" dur="1s" repeatCount="indefinite"/><animate attributeName="cy" values="26.22358709262116;49.99999999999999" keyTimes="0;1" dur="1s" repeatCount="indefinite"/><animate attributeName="fill" values="#FF708E;#51CACC" keyTimes="0;1" dur="1s" repeatCount="indefinite"/></circle></svg> <svg class="preloading-balls"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid">
<circle cx="67.802" cy="59.907" r="6" fill="#51CACC">
<animate attributeName="cx" values="75;57.72542485937369" keyTimes="0;1" dur="1s" repeatCount="indefinite"/>
<animate attributeName="cy" values="50;73.77641290737884" keyTimes="0;1" dur="1s" repeatCount="indefinite"/>
<animate attributeName="fill" values="#51CACC;#9DF871" keyTimes="0;1" dur="1s" repeatCount="indefinite"/>
</circle>
<circle cx="46.079" cy="69.992" r="6" fill="#9DF871"><animate attributeName="cx" values="57.72542485937369;29.774575140626318" keyTimes="0;1" dur="1s" repeatCount="indefinite"/>
<animate attributeName="cy" values="73.77641290737884;64.69463130731182" keyTimes="0;1" dur="1s" repeatCount="indefinite"/>
<animate attributeName="fill" values="#9DF871;#E0FF77" keyTimes="0;1" dur="1s" repeatCount="indefinite"/>
</circle><circle cx="29.775" cy="52.449" r="6" fill="#E0FF77">
<animate attributeName="cx" values="29.774575140626318;29.774575140626315" keyTimes="0;1" dur="1s" repeatCount="indefinite"/>
<animate attributeName="cy" values="64.69463130731182;35.30536869268818" keyTimes="0;1" dur="1s" repeatCount="indefinite"/>
<animate attributeName="fill" values="#E0FF77;#DE9DD6" keyTimes="0;1" dur="1s" repeatCount="indefinite"/>
</circle><circle cx="41.421" cy="31.521" r="6" fill="#DE9DD6"><animate attributeName="cx" values="29.774575140626315;57.72542485937368" keyTimes="0;1" dur="1s" repeatCount="indefinite"/>
<animate attributeName="cy" values="35.30536869268818;26.22358709262116" keyTimes="0;1" dur="1s" repeatCount="indefinite"/>
<animate attributeName="fill" values="#DE9DD6;#FF708E" keyTimes="0;1" dur="1s" repeatCount="indefinite"/>
</circle>
<circle cx="64.923" cy="36.13" r="6" fill="#FF708E"><animate attributeName="cx" values="57.72542485937368;75" keyTimes="0;1" dur="1s" repeatCount="indefinite"/>
<animate attributeName="cy" values="26.22358709262116;49.99999999999999" keyTimes="0;1" dur="1s" repeatCount="indefinite"/>
<animate attributeName="fill" values="#FF708E;#51CACC" keyTimes="0;1" dur="1s" repeatCount="indefinite"/>
</circle>
</svg>
</div> </div>
</div> </div>

@ -1 +1,20 @@
.preloading-animate{background:#ffffff;width:100%;height:100%;position:fixed;left:0;top:0;z-index:299;}.preloading-animate .preloading-wrapper{position:absolute;width:5rem;height:5rem;left:50%;top:50%;transform:translate(-50%,-50%);}.preloading-animate .preloading-wrapper .preloading-balls{font-size:5rem;} .preloading-animate{
background:#ffffff;
width:100%;
height:100%;
position:fixed;
left:0;
top:0;
z-index:299;
}
.preloading-animate .preloading-wrapper{
position:absolute;
width:5rem;
height:5rem;
left:50%;
top:50%;
transform:translate(-50%,-50%);
}
.preloading-animate .preloading-wrapper .preloading-balls{
font-size:5rem;
}

@ -1,8 +1,15 @@
// 考试相关的接口,包括考试、问题、选项和评分等接口 /**
* @description: 考试模块接口包括考试问题选项和评分等接口
*/
import api from './index' import api from './index'
import { axios } from '../utils/request' import { axios } from '../utils/request'
/**
* @description: 根据传入的参数获取问题列表
* @param {Object} parameter - 查询参数
* @returns {Promise} - 返回问题列表的Promise对象
*/
export function getQuestionList (parameter) { export function getQuestionList (parameter) {
return axios({ return axios({
url: api.ExamQuestionList, url: api.ExamQuestionList,
@ -11,6 +18,10 @@ export function getQuestionList (parameter) {
}) })
} }
/**
* @description: 获取所有问题
* @returns {Promise} - 返回所有问题的Promise对象
*/
export function getQuestionAll () { export function getQuestionAll () {
return axios({ return axios({
url: api.ExamQuestionAll, url: api.ExamQuestionAll,
@ -18,6 +29,11 @@ export function getQuestionAll () {
}) })
} }
/**
* @description: 更新问题信息
* @param {Object} parameter - 问题更新参数
* @returns {Promise} - 返回更新操作的Promise对象
*/
export function questionUpdate (parameter) { export function questionUpdate (parameter) {
console.log(parameter) console.log(parameter)
return axios({ return axios({
@ -27,6 +43,10 @@ export function questionUpdate (parameter) {
}) })
} }
/**
* @description: 获取问题的选项
* @returns {Promise} - 返回问题选项的Promise对象
*/
export function getQuestionSelection () { export function getQuestionSelection () {
return axios({ return axios({
url: api.ExamQuestionSelection, url: api.ExamQuestionSelection,
@ -37,6 +57,11 @@ export function getQuestionSelection () {
}) })
} }
/**
* @description: 创建新问题
* @param {Object} parameter - 问题创建参数
* @returns {Promise} - 返回创建操作的Promise对象
*/
export function questionCreate (parameter) { export function questionCreate (parameter) {
console.log(parameter) console.log(parameter)
return axios({ return axios({
@ -46,6 +71,11 @@ export function questionCreate (parameter) {
}) })
} }
/**
* @description: 根据传入的参数获取考试列表
* @param {Object} parameter - 查询参数
* @returns {Promise} - 返回考试列表的Promise对象
*/
export function getExamList (parameter) { export function getExamList (parameter) {
return axios({ return axios({
url: api.ExamList, url: api.ExamList,
@ -54,6 +84,10 @@ export function getExamList (parameter) {
}) })
} }
/**
* @description: 获取所有考试
* @returns {Promise} - 返回所有考试的Promise对象
*/
export function getExamAll () { export function getExamAll () {
return axios({ return axios({
url: api.ExamAll, url: api.ExamAll,
@ -61,7 +95,10 @@ export function getExamAll () {
}) })
} }
// 获取所有问题,按照单选、多选和判断进行分类 /**
* @description: 获取所有问题并按单选多选和判断进行分类
* @returns {Promise} - 返回分类问题列表的Promise对象
*/
export function getExamQuestionTypeList () { export function getExamQuestionTypeList () {
return axios({ return axios({
url: api.ExamQuestionTypeList, url: api.ExamQuestionTypeList,
@ -72,6 +109,10 @@ export function getExamQuestionTypeList () {
}) })
} }
/**
* @description: 获取考试卡片列表
* @returns {Promise} - 返回考试卡片列表的Promise对象
*/
export function getExamCardList () { export function getExamCardList () {
return axios({ return axios({
url: api.ExamCardList, url: api.ExamCardList,
@ -82,6 +123,11 @@ export function getExamCardList () {
}) })
} }
/**
* @description: 创建新考试
* @param {Object} parameter - 考试创建参数
* @returns {Promise} - 返回创建操作的Promise对象
*/
export function examCreate (parameter) { export function examCreate (parameter) {
console.log(parameter) console.log(parameter)
return axios({ return axios({
@ -91,6 +137,11 @@ export function examCreate (parameter) {
}) })
} }
/**
* @description: 更新考试信息
* @param {Object} parameter - 考试更新参数
* @returns {Promise} - 返回更新操作的Promise对象
*/
export function examUpdate (parameter) { export function examUpdate (parameter) {
console.log(parameter) console.log(parameter)
return axios({ return axios({
@ -100,6 +151,11 @@ export function examUpdate (parameter) {
}) })
} }
/**
* @description: 根据考试ID获取考试详情
* @param {String} examId - 考试ID
* @returns {Promise} - 返回考试详情的Promise对象
*/
export function getExamDetail (examId) { export function getExamDetail (examId) {
return axios({ return axios({
url: api.ExamDetail + examId, url: api.ExamDetail + examId,
@ -110,6 +166,11 @@ export function getExamDetail (examId) {
}) })
} }
/**
* @description: 根据记录ID获取考试记录详情
* @param {String} recordId - 记录ID
* @returns {Promise} - 返回考试记录详情的Promise对象
*/
export function getExamRecordDetail (recordId) { export function getExamRecordDetail (recordId) {
return axios({ return axios({
url: api.recordDetail + recordId, url: api.recordDetail + recordId,
@ -120,6 +181,11 @@ export function getExamRecordDetail (recordId) {
}) })
} }
/**
* @description: 根据问题ID获取问题详情
* @param {String} questionId - 问题ID
* @returns {Promise} - 返回问题详情的Promise对象
*/
export function getQuestionDetail (questionId) { export function getQuestionDetail (questionId) {
return axios({ return axios({
url: api.QuestionDetail + questionId, url: api.QuestionDetail + questionId,
@ -130,6 +196,12 @@ export function getQuestionDetail (questionId) {
}) })
} }
/**
* @description: 提交考试答案完成考试
* @param {String} examId - 考试ID
* @param {Object} answersMap - 答案映射
* @returns {Promise} - 返回完成考试的Promise对象
*/
export function finishExam (examId, answersMap) { export function finishExam (examId, answersMap) {
console.log(answersMap) console.log(answersMap)
return axios({ return axios({
@ -142,6 +214,10 @@ export function finishExam (examId, answersMap) {
}) })
} }
/**
* @description: 获取所有考试记录
* @returns {Promise} - 返回所有考试记录的Promise对象
*/
export function getExamRecordList () { export function getExamRecordList () {
return axios({ return axios({
url: api.ExamRecordList, url: api.ExamRecordList,

@ -1,38 +1,117 @@
/**
* @description: api接口统一管理
*/
const api = { const api = {
/**
* @description: 用户登录的接口
*/
Login: '/auth/login', Login: '/auth/login',
/**
* @description: 用户注销的接口
*/
Logout: '/auth/logout', Logout: '/auth/logout',
/**
* @description: 重置密码的接口
*/
ForgePassword: '/auth/forge-password', ForgePassword: '/auth/forge-password',
/**
* @description: 用户注册的接口
*/
Register: '/auth/register', Register: '/auth/register',
/**
* @description: 两步验证码的接口
*/
twoStepCode: '/auth/2step-code', twoStepCode: '/auth/2step-code',
/**
* @description: 发送短信的接口
*/
SendSms: '/account/sms', SendSms: '/account/sms',
/**
* @description: 发送短信错误的接口
*/
SendSmsErr: '/account/sms_err', SendSmsErr: '/account/sms_err',
// get my info /**
* @description: 获取用户信息的接口
*/
UserInfo: '/user/info', UserInfo: '/user/info',
// 下面是自己的用户认证的接口 // 下面是自己的用户认证的接口
/**
* @description: 用户注册自定义的接口
*/
UserRegister: '/user/register', UserRegister: '/user/register',
/**
* @description: 用户登录自定义的接口
*/
UserLogin: '/user/login', UserLogin: '/user/login',
// 考试的接口 // 考试的接口
/**
* @description: 获取考试问题列表的接口
*/
ExamQuestionList: '/exam/question/list', ExamQuestionList: '/exam/question/list',
/**
* @description: 获取所有考试问题的接口
*/
ExamQuestionAll: '/exam/question/all', ExamQuestionAll: '/exam/question/all',
/**
* @description: 更新考试问题的接口
*/
ExamQuestionUpdate: '/exam/question/update', ExamQuestionUpdate: '/exam/question/update',
/**
* @description: 选择考试问题的接口
*/
ExamQuestionSelection: '/exam/question/selection', ExamQuestionSelection: '/exam/question/selection',
/**
* @description: 创建考试问题的接口
*/
ExamQuestionCreate: '/exam/question/create', ExamQuestionCreate: '/exam/question/create',
/**
* @description: 获取考试列表的接口
*/
ExamList: '/exam/list', ExamList: '/exam/list',
/**
* @description: 获取所有考试的接口
*/
ExamAll: '/exam/all', ExamAll: '/exam/all',
// 获取问题列表,按照单选、多选和判断进行分类 /**
* @description: 按照单选多选和判断分类获取问题列表的接口
*/
ExamQuestionTypeList: '/exam/question/type/list', ExamQuestionTypeList: '/exam/question/type/list',
/**
* @description: 创建考试的接口
*/
ExamCreate: '/exam/create', ExamCreate: '/exam/create',
/**
* @description: 更新考试的接口
*/
ExamUpdate: '/exam/update', ExamUpdate: '/exam/update',
/**
* @description: 获取考试卡片列表的接口
*/
ExamCardList: '/exam/card/list', ExamCardList: '/exam/card/list',
// 获取考试详情 /**
* @description: 获取考试详情的接口
*/
ExamDetail: '/exam/detail/', ExamDetail: '/exam/detail/',
// 获取考试详情 /**
* @description: 获取问题详情的接口
*/
QuestionDetail: '/exam/question/detail/', QuestionDetail: '/exam/question/detail/',
// 交卷 /**
* @description: 交卷的接口
*/
FinishExam: '/exam/finish/', FinishExam: '/exam/finish/',
/**
* @description: 获取考试记录列表的接口
*/
ExamRecordList: '/exam/record/list', ExamRecordList: '/exam/record/list',
/**
* @description: 获取考试记录详情的接口
*/
recordDetail: '/exam/record/detail/' recordDetail: '/exam/record/detail/'
} }
/**
* @description: 默认导出api对象
*/
export default api export default api

@ -2,12 +2,12 @@ import api from './index'
import { axios } from '../utils/request' import { axios } from '../utils/request'
/** /**
* login func * 用户登录功能
* parameter: { * 参数: {
* username: '', * username: 用户名
* password: '', * password: 密码
* remember_me: true, * remember_me: 是否记住
* captcha: '12345' * captcha: 验证码
* } * }
* @param parameter * @param parameter
* @returns {*} * @returns {*}
@ -21,6 +21,11 @@ export function login (parameter) {
}) })
} }
/**
* 获取短信验证码
* @param parameter
* @returns {*}
*/
export function getSmsCaptcha (parameter) { export function getSmsCaptcha (parameter) {
return axios({ return axios({
url: api.SendSms, url: api.SendSms,
@ -29,6 +34,10 @@ export function getSmsCaptcha (parameter) {
}) })
} }
/**
* 获取用户信息
* @returns {*}
*/
export function getInfo () { export function getInfo () {
return axios({ return axios({
url: api.UserInfo, url: api.UserInfo,
@ -39,6 +48,10 @@ export function getInfo () {
}) })
} }
/**
* 用户登出
* @returns {*}
*/
export function logout () { export function logout () {
return axios({ return axios({
url: api.Logout, url: api.Logout,
@ -50,8 +63,9 @@ export function logout () {
} }
/** /**
* get user 2step code open? * 获取用户两步验证码开启状态
* @param parameter {*} * @param parameter
* @returns {*}
*/ */
export function get2step (parameter) { export function get2step (parameter) {
return axios({ return axios({

@ -3,6 +3,11 @@
import api from './index' import api from './index'
import { axios } from '../utils/request' import { axios } from '../utils/request'
/**
* 用户登录
* @param {Object} parameter - 登录参数
* @returns {Promise} - 返回登录请求的Promise
*/
export function login (parameter) { export function login (parameter) {
return axios({ return axios({
url: api.UserLogin, url: api.UserLogin,
@ -11,6 +16,11 @@ export function login (parameter) {
}) })
} }
/**
* 用户注册
* @param {Object} parameter - 注册参数
* @returns {Promise} - 返回注册请求的Promise
*/
export function register (parameter) { export function register (parameter) {
return axios({ return axios({
url: api.UserRegister, url: api.UserRegister,

@ -1,24 +1,33 @@
<template> <template>
<!--异常页面-->
<div class="exception"> <div class="exception">
<!--背景图-->
<div class="imgBlock"> <div class="imgBlock">
<!-- 图片元素根据传入的type动态设置背景图片 -->
<div class="imgEle" :style="{backgroundImage: `url(${config[type].img})`}"> <div class="imgEle" :style="{backgroundImage: `url(${config[type].img})`}">
</div> </div>
</div> </div>
<!-- 内容区块 -->
<div class="content"> <div class="content">
<!-- 根据传入的type动态显示标题 -->
<h1>{{ config[type].title }}</h1> <h1>{{ config[type].title }}</h1>
<!-- 根据传入的type动态显示描述 -->
<div class="desc">{{ config[type].desc }}</div> <div class="desc">{{ config[type].desc }}</div>
<!-- 操作按钮区块 -->
<div class="actions"> <div class="actions">
<!-- 点击按钮返回首页 -->
<a-button type="primary" @click="handleToHome"></a-button> <a-button type="primary" @click="handleToHome"></a-button>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script> <script>//
import types from './type' import types from './type'
export default { export default {
name: 'Exception', name: 'Exception',
//
props: { props: {
type: { type: {
type: String, type: String,
@ -27,11 +36,14 @@ export default {
}, },
data () { data () {
return { return {
//
config: types config: types
} }
}, },
methods: { methods: {
//
handleToHome () { handleToHome () {
// 使Vue Routerdashboard
this.$router.push({ name: 'dashboard' }) this.$router.push({ name: 'dashboard' })
} }
} }

@ -1,19 +1,27 @@
/**
* 定义一个常量对象types用于存储不同HTTP状态码的信息
* 每个状态码都包含一个图片URL状态码标题和描述信息
* 这些信息可以用于在界面上展示更友好的错误提示
*/
const types = { const types = {
// 403状态码信息禁止访问
403: { 403: {
img: 'https://gw.alipayobjects.com/zos/rmsportal/wZcnGqRDyhPOEYFcZDnb.svg', img: 'https://gw.alipayobjects.com/zos/rmsportal/wZcnGqRDyhPOEYFcZDnb.svg',
title: '403', title: '403',
desc: '抱歉,你无权访问该页面' desc: '抱歉,你无权访问该页面'
}, },
// 404状态码信息页面未找到
404: { 404: {
img: 'https://gw.alipayobjects.com/zos/rmsportal/KpnpchXsobRgLElEozzI.svg', img: 'https://gw.alipayobjects.com/zos/rmsportal/KpnpchXsobRgLElEozzI.svg',
title: '404', title: '404',
desc: '抱歉,你访问的页面不存在或仍在开发中' desc: '抱歉,你访问的页面不存在或仍在开发中'
}, },
// 500状态码信息服务器内部错误
500: { 500: {
img: 'https://gw.alipayobjects.com/zos/rmsportal/RVRUAYdCGeYNBWoKiIwB.svg', img: 'https://gw.alipayobjects.com/zos/rmsportal/RVRUAYdCGeYNBWoKiIwB.svg',
title: '500', title: '500',
desc: '抱歉,服务器出错了' desc: '抱歉,服务器出错了'
} }
} }
// 将types对象导出以便在其他模块中使用
export default types export default types

@ -1,18 +1,25 @@
<template> <template>
<!-- 底部信息栏 -->
<div class="footer"> <div class="footer">
<!-- 友情链接区域 -->
<div class="links"> <div class="links">
<!-- 链接项目代码仓库 -->
<a href="https://github.com/19920625lsg/spring-boot-online-exam" target="_blank">代码仓</a> <a href="https://github.com/19920625lsg/spring-boot-online-exam" target="_blank">代码仓</a>
<!-- 链接关于我的页面 -->
<a href="https://19920625lsg.github.io" target="_blank">关于我</a> <a href="https://19920625lsg.github.io" target="_blank">关于我</a>
<!-- 链接联系我 -->
<a href="mailto:liangshanguang2@gmail.com">联系我</a> <a href="mailto:liangshanguang2@gmail.com">联系我</a>
</div> </div>
<!-- 版权信息区域 -->
<div class="copyright"> <div class="copyright">
Copyright Copyright
<!-- 版权图标 -->
<a-icon type="copyright" /> 2020 <span>Liang Shan Guang</span> <a-icon type="copyright" /> 2020 <span>Liang Shan Guang</span>
</div> </div>
</div> </div>
</template> </template>
<script> <script>//
export default { export default {
name: 'GlobalFooter', name: 'GlobalFooter',
data () { data () {
@ -21,7 +28,7 @@ export default {
} }
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>//
.footer { .footer {
padding: 0 16px; padding: 0 16px;
margin: 24px 0 24px; margin: 24px 0 24px;

@ -1,22 +1,31 @@
<template> <template>
<!-- 使用 transition 组件为头部添加动画效果 -->
<transition name="showHeader"> <transition name="showHeader">
<!-- 根据 visible 属性控制头部的显示与隐藏 -->
<div v-if="visible" class="header-animat"> <div v-if="visible" class="header-animat">
<!-- 根据 visible 属性fixedHeadersidebarOpened 等属性动态设置头部样式 -->
<a-layout-header <a-layout-header
v-if="visible" v-if="visible"
:class="[fixedHeader && 'ant-header-fixedHeader', sidebarOpened ? 'ant-header-side-opened' : 'ant-header-side-closed', ]" :class="[fixedHeader && 'ant-header-fixedHeader', sidebarOpened ? 'ant-header-side-opened' : 'ant-header-side-closed', ]"
:style="{ padding: '0' }"> :style="{ padding: '0' }">
<!-- 根据 mode 属性判断菜单类型并根据不同设备类型显示不同的折叠/展开图标 -->
<div v-if="mode === 'sidemenu'" class="header"> <div v-if="mode === 'sidemenu'" class="header">
<a-icon v-if="device==='mobile'" class="trigger" :type="collapsed ? 'menu-fold' : 'menu-unfold'" @click="toggle"/> <a-icon v-if="device==='mobile'" class="trigger" :type="collapsed ? 'menu-fold' : 'menu-unfold'" @click="toggle"/>
<a-icon v-else class="trigger" :type="collapsed ? 'menu-unfold' : 'menu-fold'" @click="toggle"/> <a-icon v-else class="trigger" :type="collapsed ? 'menu-unfold' : 'menu-fold'" @click="toggle"/>
<!-- 渲染用户菜单组件 -->
<user-menu></user-menu> <user-menu></user-menu>
</div> </div>
<!-- 对于顶部菜单根据设备类型和折叠状态显示不同布局和图标 -->
<div v-else :class="['top-nav-header-index', theme]"> <div v-else :class="['top-nav-header-index', theme]">
<div class="header-index-wide"> <div class="header-index-wide">
<div class="header-index-left"> <div class="header-index-left">
<!-- 渲染 logo 组件根据设备类型决定是否显示标题 -->
<logo class="top-nav-header" :show-title="device !== 'mobile'"/> <logo class="top-nav-header" :show-title="device !== 'mobile'"/>
<!-- 根据设备类型和折叠状态渲染菜单 -->
<s-menu v-if="device !== 'mobile'" mode="horizontal" :menu="menus" :theme="theme" /> <s-menu v-if="device !== 'mobile'" mode="horizontal" :menu="menus" :theme="theme" />
<a-icon v-else class="trigger" :type="collapsed ? 'menu-fold' : 'menu-unfold'" @click="toggle" /> <a-icon v-else class="trigger" :type="collapsed ? 'menu-fold' : 'menu-unfold'" @click="toggle" />
</div> </div>
<!-- 渲染用户菜单组件 -->
<user-menu class="header-index-right"></user-menu> <user-menu class="header-index-right"></user-menu>
</div> </div>
</div> </div>
@ -25,10 +34,11 @@
</transition> </transition>
</template> </template>
<script> <script>// logo
import UserMenu from '../tools/UserMenu' import UserMenu from '../tools/UserMenu'
import SMenu from '../Menu/' import SMenu from '../Menu/'
import Logo from '../tools/Logo' import Logo from '../tools/Logo'
// 使
import { mixin } from '../../utils/mixin' import { mixin } from '../../utils/mixin'
export default { export default {
@ -39,6 +49,7 @@ export default {
Logo Logo
}, },
mixins: [mixin], mixins: [mixin],
//
props: { props: {
mode: { mode: {
type: String, type: String,
@ -67,14 +78,18 @@ export default {
}, },
data () { data () {
return { return {
//
visible: true, visible: true,
//
oldScrollTop: 0 oldScrollTop: 0
} }
}, },
// /
mounted () { mounted () {
document.body.addEventListener('scroll', this.handleScroll, { passive: true }) document.body.addEventListener('scroll', this.handleScroll, { passive: true })
}, },
methods: { methods: {
//
handleScroll () { handleScroll () {
if (!this.autoHideHeader) { if (!this.autoHideHeader) {
return return
@ -96,17 +111,19 @@ export default {
}) })
} }
}, },
// toggle
toggle () { toggle () {
this.$emit('toggle') this.$emit('toggle')
} }
}, },
//
beforeDestroy () { beforeDestroy () {
document.body.removeEventListener('scroll', this.handleScroll, true) document.body.removeEventListener('scroll', this.handleScroll, true)
} }
} }
</script> </script>
<style lang="less"> <style lang="less">//
.header-animat{ .header-animat{
position: relative; position: relative;
z-index: 2; z-index: 2;

@ -1,11 +1,14 @@
<template> <template>
<!-- 侧边栏组件包含logo和菜单 -->
<a-layout-sider <a-layout-sider
:class="['sider', isDesktop() ? null : 'shadow', theme, fixSiderbar ? 'ant-fixed-sidemenu' : null ]" :class="['sider', isDesktop() ? null : 'shadow', theme, fixSiderbar ? 'ant-fixed-sidemenu' : null ]"
width="256px" width="256px"
:collapsible="collapsible" :collapsible="collapsible"
v-model="collapsed" v-model="collapsed"
:trigger="null"> :trigger="null">
<!-- Logo组件 -->
<logo /> <logo />
<!-- 菜单组件 -->
<s-menu <s-menu
:collapsed="collapsed" :collapsed="collapsed"
:menu="menus" :menu="menus"
@ -17,7 +20,7 @@
</template> </template>
<script> <script>// LogoSMenu
import Logo from '../../components/tools/Logo' import Logo from '../../components/tools/Logo'
import SMenu from './index' import SMenu from './index'
import { mixin, mixinDevice } from '../../utils/mixin' import { mixin, mixinDevice } from '../../utils/mixin'

@ -6,20 +6,24 @@ const { Item, SubMenu } = Menu
export default { export default {
name: 'SMenu', name: 'SMenu',
props: { props: {
// 菜单数据
menu: { menu: {
type: Array, type: Array,
required: true required: true
}, },
// 主题
theme: { theme: {
type: String, type: String,
required: false, required: false,
default: 'dark' default: 'dark'
}, },
// 模式
mode: { mode: {
type: String, type: String,
required: false, required: false,
default: 'inline' default: 'inline'
}, },
// 是否折叠
collapsed: { collapsed: {
type: Boolean, type: Boolean,
required: false, required: false,
@ -28,12 +32,16 @@ export default {
}, },
data () { data () {
return { return {
// 打开的菜单项
openKeys: [], openKeys: [],
// 选择的菜单项
selectedKeys: [], selectedKeys: [],
// 缓存的打开的菜单项
cachedOpenKeys: [] cachedOpenKeys: []
} }
}, },
computed: { computed: {
// 根菜单项的key
rootSubmenuKeys: vm => { rootSubmenuKeys: vm => {
const keys = [] const keys = []
vm.menu.forEach(item => keys.push(item.path)) vm.menu.forEach(item => keys.push(item.path))
@ -41,23 +49,29 @@ export default {
} }
}, },
mounted () { mounted () {
// 组件挂载时更新菜单
this.updateMenu() this.updateMenu()
}, },
watch: { watch: {
// 监听折叠状态的变化
collapsed (val) { collapsed (val) {
if (val) { if (val) {
// 折叠时,缓存打开的菜单项
this.cachedOpenKeys = this.openKeys.concat() this.cachedOpenKeys = this.openKeys.concat()
this.openKeys = [] this.openKeys = []
} else { } else {
// 展开时,恢复打开的菜单项
this.openKeys = this.cachedOpenKeys this.openKeys = this.cachedOpenKeys
} }
}, },
// 监听路由的变化
$route: function () { $route: function () {
// 更新菜单
this.updateMenu() this.updateMenu()
} }
}, },
methods: { methods: {
// select menu item // 选择菜单项
onOpenChange (openKeys) { onOpenChange (openKeys) {
// 在水平模式下时执行,并且不再执行后续 // 在水平模式下时执行,并且不再执行后续
if (this.mode === 'horizontal') { if (this.mode === 'horizontal') {
@ -72,6 +86,7 @@ export default {
this.openKeys = latestOpenKey ? [latestOpenKey] : [] this.openKeys = latestOpenKey ? [latestOpenKey] : []
} }
}, },
// 更新菜单
updateMenu () { updateMenu () {
const routes = this.$route.matched.concat() const routes = this.$route.matched.concat()
const { hidden } = this.$route.meta const { hidden } = this.$route.meta
@ -91,13 +106,14 @@ export default {
this.collapsed ? (this.cachedOpenKeys = openKeys) : (this.openKeys = openKeys) this.collapsed ? (this.cachedOpenKeys = openKeys) : (this.openKeys = openKeys)
}, },
// render // 渲染
renderItem (menu) { renderItem (menu) {
if (!menu.hidden) { if (!menu.hidden) {
return menu.children && !menu.hideChildrenInMenu ? this.renderSubMenu(menu) : this.renderMenuItem(menu) return menu.children && !menu.hideChildrenInMenu ? this.renderSubMenu(menu) : this.renderMenuItem(menu)
} }
return null return null
}, },
// 渲染菜单项
renderMenuItem (menu) { renderMenuItem (menu) {
const target = menu.meta.target || null const target = menu.meta.target || null
const tag = target && 'a' || 'router-link' const tag = target && 'a' || 'router-link'
@ -122,6 +138,7 @@ export default {
</Item> </Item>
) )
}, },
// 渲染子菜单
renderSubMenu (menu) { renderSubMenu (menu) {
const itemArr = [] const itemArr = []
if (!menu.hideChildrenInMenu) { if (!menu.hideChildrenInMenu) {
@ -137,6 +154,7 @@ export default {
</SubMenu> </SubMenu>
) )
}, },
// 渲染图标
renderIcon (icon) { renderIcon (icon) {
if (icon === 'none' || icon === undefined) { if (icon === 'none' || icon === undefined) {
return null return null

@ -26,22 +26,35 @@
--> -->
<script> <script>
/**
* 多标签页组件
*/
export default { export default {
name: 'MultiTab', name: 'MultiTab',
data () { data () {
return { return {
// fullPath
fullPathList: [], fullPathList: [],
//
pages: [], pages: [],
// fullPath
activeKey: '', activeKey: '',
//
newTabIndex: 0 newTabIndex: 0
} }
}, },
created () { created () {
//
this.pages.push(this.$route) this.pages.push(this.$route)
this.fullPathList.push(this.$route.fullPath) this.fullPathList.push(this.$route.fullPath)
this.selectedLastPath() this.selectedLastPath()
}, },
methods: { methods: {
/**
* 处理标签页编辑事件
* @param {String} targetKey - 目标标签页的 fullPath
* @param {String} action - 操作类型例如'remove'
*/
onEdit (targetKey, action) { onEdit (targetKey, action) {
this[action](targetKey) this[action](targetKey)
}, },
@ -53,11 +66,14 @@ export default {
this.selectedLastPath() this.selectedLastPath()
} }
}, },
/**
* 选择最后一个标签页
*/
selectedLastPath () { selectedLastPath () {
this.activeKey = this.fullPathList[this.fullPathList.length - 1] this.activeKey = this.fullPathList[this.fullPathList.length - 1]
}, },
// content menu //
closeThat (e) { closeThat (e) {
this.remove(e) this.remove(e)
}, },
@ -93,6 +109,10 @@ export default {
} }
}) })
}, },
/**
* 处理右键菜单点击事件
* @param {Object} { key, item, domEvent } - 菜单项的相关信息
*/
closeMenuClick ({ key, item, domEvent }) { closeMenuClick ({ key, item, domEvent }) {
const vkey = domEvent.target.getAttribute('data-vkey') const vkey = domEvent.target.getAttribute('data-vkey')
switch (key) { switch (key) {
@ -111,6 +131,10 @@ export default {
break break
} }
}, },
/**
* 渲染标签页右键菜单
* @param {String} e - 标签页的 fullPath
*/
renderTabPaneMenu (e) { renderTabPaneMenu (e) {
return ( return (
<a-menu {...{ on: { click: this.closeMenuClick } }}> <a-menu {...{ on: { click: this.closeMenuClick } }}>
@ -122,6 +146,11 @@ export default {
) )
}, },
// render // render
/**
* 渲染标签页
* @param {String} title - 标签页的标题
* @param {String} keyPath - 标签页的 fullPath
*/
renderTabPane (title, keyPath) { renderTabPane (title, keyPath) {
const menu = this.renderTabPaneMenu(keyPath) const menu = this.renderTabPaneMenu(keyPath)
@ -133,6 +162,10 @@ export default {
} }
}, },
watch: { watch: {
/**
* 监听路由变化更新标签页列表和激活的标签页
* @param {Object} newVal - 新的路由信息
*/
'$route': function (newVal) { '$route': function (newVal) {
this.activeKey = newVal.fullPath this.activeKey = newVal.fullPath
if (this.fullPathList.indexOf(newVal.fullPath) < 0) { if (this.fullPathList.indexOf(newVal.fullPath) < 0) {
@ -140,6 +173,10 @@ export default {
this.pages.push(newVal) this.pages.push(newVal)
} }
}, },
/**
* 监听激活的标签页变化更新路由
* @param {String} newPathKey - 新的激活标签页的 fullPath
*/
activeKey: function (newPathKey) { activeKey: function (newPathKey) {
this.$router.push({ path: newPathKey }) this.$router.push({ path: newPathKey })
} }

@ -1,4 +1,6 @@
<template> <template>
<!-- 进入层展示一个通知消息组件透过点击设置触发展示-->
<!-- 通过 <a-popover> 实现通知消息框配置消息流和点击事件-->
<a-popover <a-popover
v-model="visible" v-model="visible"
trigger="click" trigger="click"
@ -9,23 +11,40 @@
:overlayStyle="{ width: '300px', top: '50px' }" :overlayStyle="{ width: '300px', top: '50px' }"
> >
<template slot="content"> <template slot="content">
<!-- 透过加载线段和标签分类显示通知 -->
<a-spin :spinning="loadding"> <a-spin :spinning="loadding">
<a-tabs> <a-tabs>
<a-tab-pane tab="通知" key="1"> <a-tab-pane tab="通知" key="1">
<!-- 显示通知列表具体消息以组件形式显示 -->
<a-list> <a-list>
<a-list-item> <a-list-item>
<a-list-item-meta title="你收到了 14 份新周报" description="一年前"> <a-list-item-meta
<a-avatar style="background-color: white" slot="avatar" src="https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png"/> title="你收到了 14 份新周报"
description="一年前">
<a-avatar
style="background-color: white"
slot="avatar"
src="https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png"/>
</a-list-item-meta> </a-list-item-meta>
</a-list-item> </a-list-item>
<a-list-item> <a-list-item>
<a-list-item-meta title="你推荐的 曲妮妮 已通过第三轮面试" description="一年前"> <a-list-item-meta
<a-avatar style="background-color: white" slot="avatar" src="https://gw.alipayobjects.com/zos/rmsportal/OKJXDXrmkNshAMvwtvhu.png"/> title="你推荐的 曲妮妮 已通过第三轮面试"
description="一年前">
<a-avatar
style="background-color: white"
slot="avatar"
src="https://gw.alipayobjects.com/zos/rmsportal/OKJXDXrmkNshAMvwtvhu.png"/>
</a-list-item-meta> </a-list-item-meta>
</a-list-item> </a-list-item>
<a-list-item> <a-list-item>
<a-list-item-meta title="这种模板可以区分多种通知类型" description="一年前"> <a-list-item-meta
<a-avatar style="background-color: white" slot="avatar" src="https://gw.alipayobjects.com/zos/rmsportal/kISTdvpyTAhtGxpovNWd.png"/> title="这种模板可以区分多种通知类型"
description="一年前">
<a-avatar
style="background-color: white"
slot="avatar"
src="https://gw.alipayobjects.com/zos/rmsportal/kISTdvpyTAhtGxpovNWd.png"/>
</a-list-item-meta> </a-list-item-meta>
</a-list-item> </a-list-item>
</a-list> </a-list>
@ -39,6 +58,7 @@
</a-tabs> </a-tabs>
</a-spin> </a-spin>
</template> </template>
<!-- 点击回调消息分类加载功能 -->
<span @click="fetchNotice" class="header-notice"> <span @click="fetchNotice" class="header-notice">
<a-badge count="12"> <a-badge count="12">
<a-icon style="font-size: 16px; padding: 4px" type="bell" /> <a-icon style="font-size: 16px; padding: 4px" type="bell" />
@ -49,41 +69,45 @@
<script> <script>
export default { export default {
name: 'HeaderNotice', name: 'HeaderNotice', //
data () { data () {
return { return {
loadding: false, loadding: false, //
visible: false visible: false //
} }
}, },
methods: { methods: {
//
fetchNotice () { fetchNotice () {
if (!this.visible) { if (!this.visible) {
this.loadding = true this.loadding = true
//
setTimeout(() => { setTimeout(() => {
this.loadding = false this.loadding = false
}, 2000) }, 2000)
} else { } else {
this.loadding = false this.loadding = false
} }
this.visible = !this.visible this.visible = !this.visible //
} }
} }
} }
</script> </script>
<style lang="css"> <style lang="css">
.header-notice-wrapper { /* 通知框样式配置 */
.header-notice-wrapper {
top: 50px !important; top: 50px !important;
} }
</style> </style>
<style lang="less" scoped> <style lang="less" scoped>
.header-notice{ /* 层级框样式 */
.header-notice{
display: inline-block; display: inline-block;
transition: all 0.3s; transition: all 0.3s;
span { span {
vertical-align: initial; vertical-align: initial;
} }
} }
</style> </style>

@ -1,28 +1,38 @@
<template> <template>
<!-- 页面头部组件 -->
<div class="page-header"> <div class="page-header">
<div class="page-header-index-wide"> <div class="page-header-index-wide">
<!-- 面包屑导航 -->
<s-breadcrumb /> <s-breadcrumb />
<div class="detail"> <div class="detail">
<!-- 主要内容区域 -->
<div class="main" v-if="!$route.meta.hiddenHeaderContent"> <div class="main" v-if="!$route.meta.hiddenHeaderContent">
<div class="row"> <div class="row">
<!-- Logo图片 -->
<img v-if="logo" :src="logo" class="logo"/> <img v-if="logo" :src="logo" class="logo"/>
<!-- 页面标题 -->
<h1 v-if="title" class="title">{{ title }}</h1> <h1 v-if="title" class="title">{{ title }}</h1>
<!-- 自定义操作区域 -->
<div class="action"> <div class="action">
<slot name="action"></slot> <slot name="action"></slot>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<!-- 头像 -->
<div v-if="avatar" class="avatar"> <div v-if="avatar" class="avatar">
<a-avatar :src="avatar" /> <a-avatar :src="avatar" />
</div> </div>
<!-- 自定义内容区域 -->
<div v-if="this.$slots.content" class="headerContent"> <div v-if="this.$slots.content" class="headerContent">
<slot name="content"></slot> <slot name="content"></slot>
</div> </div>
<!-- 额外的自定义区域 -->
<div v-if="this.$slots.extra" class="extra"> <div v-if="this.$slots.extra" class="extra">
<slot name="extra"></slot> <slot name="extra"></slot>
</div> </div>
</div> </div>
<div> <div>
<!-- 页面菜单 -->
<slot name="pageMenu"></slot> <slot name="pageMenu"></slot>
</div> </div>
</div> </div>
@ -31,25 +41,28 @@
</div> </div>
</template> </template>
<script> <script>//
import Breadcrumb from '../../components/tools/Breadcrumb' import Breadcrumb from '../../components/tools/Breadcrumb'
//
export default { export default {
name: 'PageHeader', name: 'PageHeader',
components: { components: {
's-breadcrumb': Breadcrumb 's-breadcrumb': Breadcrumb
}, },
props: { props: {
// true
title: { title: {
type: [String, Boolean], type: [String, Boolean],
default: true, default: true,
required: false required: false
}, },
// Logo
logo: { logo: {
type: String, type: String,
default: '', default: '',
required: false required: false
}, },
//
avatar: { avatar: {
type: String, type: String,
default: '', default: '',
@ -62,7 +75,7 @@ export default {
} }
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>//
.page-header { .page-header {
background: #fff; background: #fff;
padding: 16px 32px 0; padding: 16px 32px 0;
@ -152,7 +165,7 @@ export default {
} }
} }
} }
//
.mobile .page-header { .mobile .page-header {
.main { .main {
.row { .row {

@ -1,28 +1,34 @@
<template> <template>
<!-- 结果展示组件 -->
<div class="result"> <div class="result">
<!-- 根据成功或错误状态动态显示对应图标 -->
<div> <div>
<a-icon :class="{ 'icon': true, [`${type}`]: true }" :type="localIsSuccess ? 'check-circle' : 'close-circle'"/> <a-icon :class="{ 'icon': true, [`${type}`]: true }" :type="localIsSuccess ? 'check-circle' : 'close-circle'"/>
</div> </div>
<!-- 标题区域支持自定义插槽内容 -->
<div class="title"> <div class="title">
<slot name="title"> <slot name="title">
{{ title }} {{ title }}
</slot> </slot>
</div> </div>
<!-- 描述区域支持自定义插槽内容 -->
<div class="description"> <div class="description">
<slot name="description"> <slot name="description">
{{ description }} {{ description }}
</slot> </slot>
</div> </div>
<!-- 额外信息区域根据插槽内容动态显示 -->
<div class="extra" v-if="$slots.default"> <div class="extra" v-if="$slots.default">
<slot></slot> <slot></slot>
</div> </div>
<!-- 操作区域根据插槽内容动态显示 -->
<div class="action" v-if="$slots.action"> <div class="action" v-if="$slots.action">
<slot name="action"></slot> <slot name="action"></slot>
</div> </div>
</div> </div>
</template> </template>
<script> <script>//
const resultEnum = ['success', 'error'] const resultEnum = ['success', 'error']
export default { export default {
@ -33,6 +39,7 @@ export default {
type: Boolean, type: Boolean,
default: false default: false
}, },
// success error
type: { type: {
type: String, type: String,
default: resultEnum[0], default: resultEnum[0],
@ -40,16 +47,19 @@ export default {
return (val) => resultEnum.includes(val) return (val) => resultEnum.includes(val)
} }
}, },
//
title: { title: {
type: String, type: String,
default: '' default: ''
}, },
//
description: { description: {
type: String, type: String,
default: '' default: ''
} }
}, },
computed: { computed: {
//
localIsSuccess: function () { localIsSuccess: function () {
return this.type === resultEnum[0] return this.type === resultEnum[0]
} }
@ -69,9 +79,11 @@ export default {
line-height: 72px; line-height: 72px;
margin-bottom: 24px; margin-bottom: 24px;
} }
//
.success { .success {
color: #52c41a; color: #52c41a;
} }
//
.error { .error {
color: red; color: red;
} }

@ -1,12 +1,22 @@
<template> <template>
<!-- 设置项容器 -->
<div class="setting-drawer-index-item"> <div class="setting-drawer-index-item">
<!-- 设置项标题 -->
<h3 class="setting-drawer-index-title">{{ title }}</h3> <h3 class="setting-drawer-index-title">{{ title }}</h3>
<!-- 插槽内容用于显示设置项的具体内容 -->
<slot></slot> <slot></slot>
<!-- 根据props中的divider决定是否显示分割线 -->
<a-divider v-if="divider"/> <a-divider v-if="divider"/>
</div> </div>
</template> </template>
<script> <script>
/**
* 设置项组件
*
* @param {String} title - 设置项的标题默认为空字符串
* @param {Boolean} divider - 是否显示设置项后的分割线默认不显示
*/
export default { export default {
name: 'SettingItem', name: 'SettingItem',
props: { props: {
@ -22,11 +32,11 @@ export default {
} }
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>/* 设置项样式 */
.setting-drawer-index-item { .setting-drawer-index-item {
margin-bottom: 24px; margin-bottom: 24px;
/* 设置项标题样式 */
.setting-drawer-index-title { .setting-drawer-index-title {
font-size: 14px; font-size: 14px;
color: rgba(0, 0, 0, .85); color: rgba(0, 0, 0, .85);

@ -1,15 +1,18 @@
<template> <template>
<!-- 标准表单行组件根据不同的属性组合有不同的样式表现 -->
<div :class="[prefixCls, lastCls, blockCls, gridCls]"> <div :class="[prefixCls, lastCls, blockCls, gridCls]">
<!-- 标题部分只有当title属性存在时才显示 -->
<div v-if="title" class="antd-pro-components-standard-form-row-index-label"> <div v-if="title" class="antd-pro-components-standard-form-row-index-label">
<span>{{ title }}</span> <span>{{ title }}</span>
</div> </div>
<!-- 内容部分使用slot以便于自定义内容 -->
<div class="antd-pro-components-standard-form-row-index-content"> <div class="antd-pro-components-standard-form-row-index-content">
<slot></slot> <slot></slot>
</div> </div>
</div> </div>
</template> </template>
<script> <script>//
const classes = [ const classes = [
'antd-pro-components-standard-form-row-index-standardFormRowBlock', 'antd-pro-components-standard-form-row-index-standardFormRowBlock',
'antd-pro-components-standard-form-row-index-standardFormRowGrid', 'antd-pro-components-standard-form-row-index-standardFormRowGrid',
@ -17,6 +20,7 @@ const classes = [
] ]
export default { export default {
name: 'StandardFormRow', name: 'StandardFormRow',
//
props: { props: {
prefixCls: { prefixCls: {
type: String, type: String,
@ -36,6 +40,7 @@ export default {
type: Boolean type: Boolean
} }
}, },
// props
computed: { computed: {
lastCls () { lastCls () {
return this.last ? classes[2] : null return this.last ? classes[2] : null
@ -50,9 +55,9 @@ export default {
} }
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>//
@import '../index.less'; @import '../index.less';
//
.antd-pro-components-standard-form-row-index-standardFormRow { .antd-pro-components-standard-form-row-index-standardFormRow {
display: flex; display: flex;
margin-bottom: 16px; margin-bottom: 16px;
@ -71,7 +76,7 @@ export default {
padding: 0; padding: 0;
line-height: 32px; line-height: 32px;
} }
//
.antd-pro-components-standard-form-row-index-label { .antd-pro-components-standard-form-row-index-label {
flex: 0 0 auto; flex: 0 0 auto;
margin-right: 24px; margin-right: 24px;
@ -87,27 +92,27 @@ export default {
} }
} }
} }
//
.antd-pro-components-standard-form-row-index-content { .antd-pro-components-standard-form-row-index-content {
flex: 1 1 0; flex: 1 1 0;
/deep/ .ant-form-item:last-child { /deep/ .ant-form-item:last-child {
margin-right: 0; margin-right: 0;
} }
} }
//
&.antd-pro-components-standard-form-row-index-standardFormRowLast { &.antd-pro-components-standard-form-row-index-standardFormRowLast {
margin-bottom: 0; margin-bottom: 0;
padding-bottom: 0; padding-bottom: 0;
border: none; border: none;
} }
// 使block
&.antd-pro-components-standard-form-row-index-standardFormRowBlock { &.antd-pro-components-standard-form-row-index-standardFormRowBlock {
/deep/ .ant-form-item, /deep/ .ant-form-item,
div.ant-form-item-control-wrapper { div.ant-form-item-control-wrapper {
display: block; display: block;
} }
} }
// 使grid
&.antd-pro-components-standard-form-row-index-standardFormRowGrid { &.antd-pro-components-standard-form-row-index-standardFormRowGrid {
/deep/ .ant-form-item, /deep/ .ant-form-item,
div.ant-form-item-control-wrapper { div.ant-form-item-control-wrapper {

@ -7,7 +7,9 @@
* @param children * @param children
* @returns {*[]} * @returns {*[]}
*/ */
// 导出一个函数,用于过滤掉空节点
export function filterEmpty (children = []) { export function filterEmpty (children = []) {
// 过滤掉没有tag属性和text属性为空字符串的节点
return children.filter(c => c.tag || (c.text && c.text.trim() !== '')) return children.filter(c => c.tag || (c.text && c.text.trim() !== ''))
} }
@ -15,12 +17,17 @@ export function filterEmpty (children = []) {
* 获取字符串长度英文字符 长度1中文字符长度2 * 获取字符串长度英文字符 长度1中文字符长度2
* @param {*} str * @param {*} str
*/ */
// 导出一个函数,用于获取字符串长度
export const getStrFullLength = (str = '') => export const getStrFullLength = (str = '') =>
// 将字符串分割成字符数组然后使用reduce方法遍历数组计算每个字符的长度
str.split('').reduce((pre, cur) => { str.split('').reduce((pre, cur) => {
// 获取字符的Unicode编码
const charCode = cur.charCodeAt(0) const charCode = cur.charCodeAt(0)
// 如果字符的Unicode编码在0-128之间说明是英文字符长度为1
if (charCode >= 0 && charCode <= 128) { if (charCode >= 0 && charCode <= 128) {
return pre + 1 return pre + 1
} }
// 否则说明是中文字符长度为2
return pre + 2 return pre + 2
}, 0) }, 0)
@ -29,18 +36,26 @@ export const getStrFullLength = (str = '') =>
* @param {*} str * @param {*} str
* @param {*} maxLength * @param {*} maxLength
*/ */
// 导出一个函数,用于截取字符串
export const cutStrByFullLength = (str = '', maxLength) => { export const cutStrByFullLength = (str = '', maxLength) => {
// 初始化显示长度为0
let showLength = 0 let showLength = 0
// 将字符串分割成字符数组然后使用reduce方法遍历数组截取字符串
return str.split('').reduce((pre, cur) => { return str.split('').reduce((pre, cur) => {
// 获取字符的Unicode编码
const charCode = cur.charCodeAt(0) const charCode = cur.charCodeAt(0)
// 如果字符的Unicode编码在0-128之间说明是英文字符长度为1
if (charCode >= 0 && charCode <= 128) { if (charCode >= 0 && charCode <= 128) {
showLength += 1 showLength += 1
} else { } else {
// 否则说明是中文字符长度为2
showLength += 2 showLength += 2
} }
// 如果显示长度小于等于maxLength则将字符添加到结果中
if (showLength <= maxLength) { if (showLength <= maxLength) {
return pre + cur return pre + cur
} }
// 否则,返回结果
return pre return pre
}, '') }, '')
} }

@ -1,6 +1,9 @@
<template> <template>
<!-- 面包屑组件 -->
<a-breadcrumb class="breadcrumb"> <a-breadcrumb class="breadcrumb">
<!-- 遍历面包屑列表生成每个面包屑项 -->
<a-breadcrumb-item v-for="(item, index) in breadList" :key="item.name"> <a-breadcrumb-item v-for="(item, index) in breadList" :key="item.name">
<!-- 根据条件渲染面包屑项的链接或文本 -->
<router-link <router-link
v-if="item.name != name && index != 1" v-if="item.name != name && index != 1"
:to="{ path: item.path === '' ? '/' : item.path }" :to="{ path: item.path === '' ? '/' : item.path }"
@ -14,26 +17,35 @@
export default { export default {
data () { data () {
return { return {
//
name: '', name: '',
//
breadList: [] breadList: []
} }
}, },
created () { created () {
//
this.getBreadcrumb() this.getBreadcrumb()
}, },
methods: { methods: {
/**
* 获取面包屑信息
* 该方法根据当前路由生成面包屑列表
*/
getBreadcrumb () { getBreadcrumb () {
this.breadList = [] this.breadList = []
// this.breadList.push({name: 'index', path: '/dashboard/', meta: {title: ''}}) // this.breadList.push({name: 'index', path: '/dashboard/', meta: {title: ''}})
//
this.name = this.$route.name this.name = this.$route.name
this.$route.matched.forEach(item => { this.$route.matched.forEach(item => {
// item.name !== 'index' && this.breadList.push(item) // item.name !== 'index' && this.breadList.push(item)
//
this.breadList.push(item) this.breadList.push(item)
}) })
} }
}, },
watch: { watch: {
//
$route () { $route () {
this.getBreadcrumb() this.getBreadcrumb()
} }

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save