Compare commits

..

No commits in common. 'feature/lxh' and 'main' have entirely different histories.

2
.gitignore vendored

@ -21,5 +21,3 @@
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid* hs_err_pid*
**/.idea

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

@ -1,6 +0,0 @@
<?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>

@ -1,69 +1,6 @@
<component name="InspectionProjectProfileManager"> <component name="InspectionProjectProfileManager">
<profile version="1.0"> <profile version="1.0">
<option name="myName" value="Project Default" /> <option name="myName" value="Project Default" />
<inspection_tool class="AliAccessStaticViaInstance" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AliArrayNamingShouldHaveBracket" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AliControlFlowStatementWithoutBraces" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AliDeprecation" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AliEqualsAvoidNull" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AliLongLiteralsEndingWithLowercaseL" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AliMissingOverrideAnnotation" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AliWrapperTypeEquality" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaAbstractClassShouldStartWithAbstractNaming" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaAbstractMethodOrInterfaceMethodMustUseJavadoc" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaAvoidApacheBeanUtilsCopy" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaAvoidCallStaticSimpleDateFormat" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaAvoidCommentBehindStatement" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaAvoidComplexCondition" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaAvoidConcurrentCompetitionRandom" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaAvoidDoubleOrFloatEqualCompare" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaAvoidManuallyCreateThread" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaAvoidMissUseOfMathRandom" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaAvoidNegationOperator" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaAvoidNewDateGetTime" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaAvoidPatternCompileInMethod" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaAvoidReturnInFinally" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaAvoidStartWithDollarAndUnderLineNaming" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaAvoidUseTimer" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaBigDecimalAvoidDoubleConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaBooleanPropertyShouldNotStartWithIs" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaClassCastExceptionWithSubListToArrayList" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaClassCastExceptionWithToArray" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaClassMustHaveAuthor" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaClassNamingShouldBeCamel" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaCollectionInitShouldAssignCapacity" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaCommentsMustBeJavadocFormat" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaConcurrentExceptionWithModifyOriginSubList" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaConstantFieldShouldBeUpperCase" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaCountDownShouldInFinally" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaDontModifyInForeachCircle" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaEnumConstantsMustHaveComment" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaExceptionClassShouldEndWithException" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaIbatisMethodQueryForList" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaLockShouldWithTryFinally" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaLowerCamelCaseVariableNaming" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaMethodReturnWrapperType" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaMethodTooLong" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaPackageNaming" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaPojoMustOverrideToString" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaPojoMustUsePrimitiveField" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaPojoNoDefaultValue" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaRemoveCommentedCode" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaServiceOrDaoClassShouldEndWithImpl" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaSneakyThrowsWithoutExceptionType" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaStringConcat" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaSwitchExpression" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaSwitchStatement" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaTestClassShouldEndWithTestNaming" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaThreadLocalShouldRemove" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaThreadPoolCreation" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaThreadShouldSetName" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaTransactionMustHaveRollback" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaUndefineMagicConstant" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaUnsupportedExceptionWithModifyAsList" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaUseQuietReferenceNotation" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AlibabaUseRightCaseForDateFormat" enabled="true" level="WARNING" enabled_by_default="true" />
<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>

@ -1,20 +0,0 @@
<?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>

@ -1,124 +0,0 @@
<?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>

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="VcsDirectoryMappings"> <component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" /> <mapping directory="$PROJECT_DIR$/.." vcs="Git" />
</component> </component>
</project> </project>

@ -1,18 +1,108 @@
ResultVO<RecordDetailVo> getExamRecordDetail(@PathVariable String recordId) { # spring-boot-online-exam
// 定义返回结果
ResultVO<RecordDetailVo> resultVO; > 在线Demo预览http://129.211.88.191 账户分别是admin、teacher、student密码是admin123。视频讲解代码https://www.bilibili.com/video/BV1FP4y1L7xt/
try {
// 调用examService获取考试记录详情 > 好消息一个小伙伴做了Python实现欢迎大家starhttps://github.com/xingxingzaixian/django-drf-online-exam
RecordDetailVo recordDetailVo = examService.getRecordDetail(recordId);
// 返回成功结果 ## 1.快速体验
resultVO = new ResultVO<>(0, "获取考试记录详情成功", recordDetailVo); ### 1.1 事先准备
} catch (Exception e) { > clone代码并进入代码路径
// 打印异常信息
e.printStackTrace(); ```shell
// 返回失败结果 git clone git@github.com:lsgwr/spring-boot-online-exam.git
resultVO = new ResultVO<>(-1, "获取考试记录详情失败", null); cd spring-boot-online-exam
} ```
// 返回结果
return resultVO; 下面按照Linux和windows说明快速搭建的方法
} ### 1.2 Linux
} 执行代码下的脚本start.sh即可
然后访问 http://ip:80 即可访问自己搭建的考试系统
### 1.3 windows
+ 1.安装JDK推荐JDK8
+ 2.从官方仓库下载发布的jar包建议选择最新版https://github.com/lsgwr/spring-boot-online-exam/releases
+ 3.安装MySQL创建数据库exam并初始化密码为aA111111导入doc/sql/exam.sql文件来创建数据库
+ 4.启动jar包`java -jar exam.jar`
+ 5.访问http://ip:9527 即可访问自己搭建的考试系统
## 2.介绍
基于springboot的在线考试系统
### 2.1 功能简介
+ 支持单选题、多选题、判断题
+ 支持学生(student)、教师(teacher)、管理员(admin)三种角色
+ 学生:参加考试和查看我的考试
+ 教师:学生的所有权限+创建/编辑题目+创建/编辑考试
+ 管理员:教师的所有权限+管理用户
### 2.3 软件架构
> 前后端分离,前段组件化,方便二次开发;后端
+ 后端采用SpringBoot+JPA++Swagger2+JWT校验,根据不同用户的权限返回给用户不同的数据
+ 后端采用Vue+AntDesign,组件化拆分,封装了很多年公共组件,方便维护和二次开发
### 2.3 使用教程
+ 1.下载代码
```shell
git clone https://github.com/19920625lsg/spring-boot-online-exam.git
```
+ 2.初始化数据库
> 安装mysql的步骤这里省略网上的教程很多。安装好mysql后新建exam数据库密码和`spring-boot-online-exam/backend/exam/src/main/resources/application.yml`的`password: xxxxxx`保持一致,然后导入`spring-boot-online-exam/doc/sql/exam.sql`
+ 3.启动后端
> 打开`spring-boot-online-exam/backend/exam`这个Maven项目可以在IDE里启动或者执行`mvn install`生成jar包启动
+ 4.启动前端
+ 进入到前端代码路径 `cd spring-boot-online-exam/frontend/exam/`
+ 安装依赖 `npm install`
+ 启动前端 `npm run serve`
+ 5.部署完毕,查看效果
> 打开 http://localhost:8000 或者 http://本机ip:8000 即可查看演示效果
## 3.功能图示
+ 1.管理题目
+ 1.1 题目列表
> ![题目查看](doc/images/question_list.png)
+ 1.2 题目创建
> ![题目创建](doc/images/question_create.png)
+ 1.3 题目更新
> ![题目更新](doc/images/question_update.png)
+ 2.考试管理
+ 2.1 考试列表
> ![考试查看](doc/images/exam_list.png)
+ 2.2 考试创建
> ![考试创建](doc/images/exam_create.png)
+ 2.3 考试更新(`还有点小bug开发中`)
> ![考试更新](doc/images/exam_update.png)
+ 3.我的考试
+ 3.1 参加考试
> 在"考试列表"模块点击自己想参加的考试卡片即可
> ![参加考试1](doc/images/exam_join.png)
> ![参加考试2](doc/images/exam_join2.png)
+ 3.2 考试记录查看
> ![考试记录查看](doc/images/exam_detail.png)
## 4.参与贡献
1. Fork 本仓库
2. 新建 exam_xxx 分支
3. 提交代码
4. 新建 Pull Request
## 5.Todo
+ `√`0.修复issue提地bug题目创建失败
+ `√`1.考试详情编辑
+ 2.支持题目和考试的删除`删除的话比较麻烦先不做了最好是弄个visible字段不实际删除要不后面有些关联数据找不到就不好了`
> 如果题目有关联的考试则必须先删除对应的考试,反过来删除考试则不用删除题目
+ 3.图片改成base64存到数据库中
+ 4.题干和选项支持富文本
+ 5.支持批量导入题目
+ 6.新增用户管理、学科管理功能
+ 7.老师能考到所有学生的成绩以及考试的统计信息
+ 8.更多的数据分析功能
+ 9.支持容器化一键式部署(编好Dockerfile)
+ 10.支持移动端最好用uniapp做
+ ......抓紧做吧,争取每周末做一点......

@ -3,9 +3,6 @@ package lsgwr.exam;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* Spring BootSpring Boot
*/
@SpringBootApplication @SpringBootApplication
public class ExamApplication { public class ExamApplication {

@ -22,235 +22,166 @@ import java.util.List;
@RestController @RestController
@Api(tags = "Exam APIs") @Api(tags = "Exam APIs")
//将此控制器中的所有端点映射到/api/exam URL路径
@RequestMapping("/api/exam") @RequestMapping("/api/exam")
public class ExamController { public class ExamController {
@Autowired //注入一个ExamService实例用于处理与考试和问题相关的业务逻辑 @Autowired
private ExamService examService; private ExamService examService;
/**
* @Description: 使examService.getQuestionAll(),ResultVO,
* &#064;ApiOperationAPI,SwaggerUI
*/
@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;
} }
@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);
} }
} }
/**
*
* @Description: QuestionCreateSimplifyVoQuestionCreateVoID使examService.questionCreate()
* @param questionCreateSimplifyVo QuestionCreateSimplifyVo
* @param request HttpServletRequestID
* @return ResultVO<String>
*/
@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);
} }
} }
/**
* @Description: ,使examService.getSelections()ResultVO
* @return ResultVO<QuestionAllVo>
*/
@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);
} }
} }
@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 = new ResultVO<>(-1, "获取问题详情失败", null); resultVO = new ResultVO<>(-1, "获取问题详情失败", null);
} }
// 返回ResultVO对象。
return resultVO; return resultVO;
} }
@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;
} }
@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;
} }
@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; ResultVO<Exam> resultVO;
// 获取当前用户的id。
String userId = (String) request.getAttribute("user_id"); String userId = (String) request.getAttribute("user_id");
try { try {
// 调用examService的create方法将examCreateVo和userId作为参数传入创建考试。
Exam exam = examService.create(examCreateVo, userId); Exam exam = examService.create(examCreateVo, userId);
// 创建一个ResultVO对象将创建成功的考试信息返回。
resultVO = new ResultVO<>(0, "创建考试成功", exam); resultVO = new ResultVO<>(0, "创建考试成功", exam);
} catch (Exception e) { } catch (Exception e) {
// 捕获异常打印异常信息并创建一个ResultVO对象将创建失败的考试信息返回。
e.printStackTrace(); e.printStackTrace();
resultVO = new ResultVO<>(-1, "创建考试失败", null); resultVO = new ResultVO<>(-1, "创建考试失败", null);
} }
// 返回ResultVO对象。
return resultVO; return resultVO;
} }
@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:
* @return ResultVO<List<ExamCardVo>>
*/
@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 = new ResultVO<>(0, "获取考试列表卡片成功", examCardVoList); resultVO = new ResultVO<>(0, "获取考试列表卡片成功", examCardVoList);
} 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: id
* @param id id
* @return ResultVO<ExamDetailVo>
*/
@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; ResultVO<ExamDetailVo> resultVO;
try { try {
ExamDetailVo examDetail = examService.getExamDetail(id); ExamDetailVo examDetail = examService.getExamDetail(id);
@ -261,48 +192,31 @@ ResultVO<QuestionSelectionVo> getSelections() {
return resultVO; return resultVO;
} }
/**
* @Description: 使examService.finishExam,ResultVO,
* @param examId id
* @param answersMap
* @param request id
* @return
*/
@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; ResultVO<ExamRecord> resultVO;
try { try {
// 拦截器里设置上的用户id // 拦截器里设置上的用户id
String userId = (String) request.getAttribute("user_id"); String userId = (String) request.getAttribute("user_id");
// 下面根据用户提交的信息进行判分,返回用户的得分情况 // 下面根据用户提交的信息进行判分,返回用户的得分情况
ExamRecord examRecord = examService.judge(userId, examId, answersMap); ExamRecord examRecord = examService.judge(userId, examId, answersMap);
// 返回结果。
resultVO = new ResultVO<>(0, "考卷提交成功", examRecord); resultVO = new ResultVO<>(0, "考卷提交成功", examRecord);
} 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: 使examService.getExamRecordList,ResultVO,
* @param request id
* @return ResultVO<List<ExamRecordVo>> ResultVOResultVO
*/
@GetMapping("/record/list") @GetMapping("/record/list")
@ApiOperation("获取当前用户的考试记录") @ApiOperation("获取当前用户的考试记录")
// 获取考试记录列表。
ResultVO<List<ExamRecordVo>> getExamRecordList(HttpServletRequest request) { ResultVO<List<ExamRecordVo>> getExamRecordList(HttpServletRequest request) {
ResultVO<List<ExamRecordVo>> resultVO; ResultVO<List<ExamRecordVo>> resultVO;
try { try {
// 拦截器里设置上的用户id // 拦截器里设置上的用户id
String userId = (String) request.getAttribute("user_id"); String userId = (String) request.getAttribute("user_id");
// 下面根据用户账号拿到他(她所有的考试信息)注意要用VO封装下 // 下面根据用户账号拿到他(她所有的考试信息)注意要用VO封装下
List<ExamRecordVo> examRecordVoList = examService.getExamRecordList(userId); List<ExamRecordVo> examRecordVoList = examService.getExamRecordList(userId);
resultVO = new ResultVO<>(0, "获取考试记录成功", examRecordVoList); resultVO = new ResultVO<>(0, "获取考试记录成功", examRecordVoList);
} catch (Exception e) { } catch (Exception e) {
@ -312,28 +226,17 @@ ResultVO<QuestionSelectionVo> getSelections() {
return resultVO; return resultVO;
} }
/**
* @Description: 使examService.getExamRecordDetail,ResultVO,id
* @param recordId id
* @return ResultVO<RecordDetailVo> ResultVOResultVO
*/
@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; ResultVO<RecordDetailVo> resultVO;
try { try {
// 调用examService获取考试记录详情。
RecordDetailVo recordDetailVo = examService.getRecordDetail(recordId); RecordDetailVo recordDetailVo = examService.getRecordDetail(recordId);
// 返回成功结果。
resultVO = new ResultVO<>(0, "获取考试记录详情成功", recordDetailVo); resultVO = new ResultVO<>(0, "获取考试记录详情成功", recordDetailVo);
} catch (Exception e) { } catch (Exception e) {
// 打印异常信息。
e.printStackTrace(); e.printStackTrace();
// 返回失败结果。
resultVO = new ResultVO<>(-1, "获取考试记录详情失败", null); resultVO = new ResultVO<>(-1, "获取考试记录详情失败", null);
} }
// 返回结果。
return resultVO; return resultVO;
} }
} }

@ -42,49 +42,37 @@ public class UploadDownloadController {
@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) {
// 调用FileTransUtil工具类中的uploadFile方法将上传的文件和目录作为参数传入。
return FileTransUtil.uploadFile(uploadfile, dir); return FileTransUtil.uploadFile(uploadfile, dir);
} }
// 单文件上传支持同时传入参数Model。
@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) {
// 调用FileTransUtil工具类中的uploadFile方法将上传的文件和目录作为参数传入。
return FileTransUtil.uploadFile(model.getFile(), model.getDir()); return FileTransUtil.uploadFile(model.getFile(), model.getDir());
} }
// 多文件上传,支持同时传入参数。
@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) {
// 调用FileTransUtil工具类中的uploadFiles方法将上传的文件数组和目录作为参数传入。
return FileTransUtil.uploadFiles(uploadfiles, dir); return FileTransUtil.uploadFiles(uploadfiles, dir);
} }
// 多文件上传,支持同时传入参数。
@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) {
// 调用FileTransUtil工具类中的uploadFiles方法将上传的文件数组和目录作为参数传入。
return FileTransUtil.uploadFiles(model.getFiles(), model.getDir()); return FileTransUtil.uploadFiles(model.getFiles(), model.getDir());
} }
// Get下载文件
@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 {
// 调用FileTransUtil工具类中的downloadFile方法将文件路径作为参数传入。
return FileTransUtil.downloadFile(filePath); return FileTransUtil.downloadFile(filePath);
} }
// Post下载文件
@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 {
// 调用FileTransUtil工具类中的downloadFile方法将文件路径作为参数传入。
return FileTransUtil.downloadFile(downloadQo.getPath()); return FileTransUtil.downloadFile(downloadQo.getPath());
} }
} }

@ -62,27 +62,18 @@ public class UserController {
@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);
} }
@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);
} }

@ -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.repository.*;
import lsgwr.exam.service.ExamService; import lsgwr.exam.service.ExamService;
import lsgwr.exam.repository.*;
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;
@ -40,9 +40,9 @@ public class ExamServiceImpl implements ExamService {
private final QuestionOptionRepository questionOptionRepository; private final QuestionOptionRepository questionOptionRepository;
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;
this.questionLevelRepository = questionLevelRepository;// this.questionLevelRepository = questionLevelRepository;
this.questionTypeRepository = questionTypeRepository; this.questionTypeRepository = questionTypeRepository;
this.questionCategoryRepository = questionCategoryRepository; this.questionCategoryRepository = questionCategoryRepository;
this.questionOptionRepository = questionOptionRepository; this.questionOptionRepository = questionOptionRepository;
@ -57,9 +57,9 @@ public class ExamServiceImpl implements ExamService {
} }
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 +69,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 +79,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 +87,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 +95,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 +104,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 +129,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 +148,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,64 +175,58 @@ 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;
} }
@ -251,15 +245,10 @@ 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(
@ -269,10 +258,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;
@ -285,14 +274,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(
@ -301,7 +290,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("-"))
@ -309,12 +298,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("-"))
@ -322,12 +311,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("-"))
@ -335,7 +324,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);
@ -351,7 +340,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) {
@ -361,7 +350,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) {
@ -371,7 +360,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) {
@ -385,7 +374,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());
@ -393,50 +382,32 @@ 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++;
} }
} }
@ -456,64 +427,49 @@ 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.setExamCreatorId(userId); exam.setUpdateTime(new Date()); // 考试的更新日期要记录下
// 记录考试更新日期
exam.setUpdateTime(new Date());
// 初始化选择题、判断题、单选题的id字符串
String radioIdsStr = ""; String radioIdsStr = "";
String checkIdsStr = ""; String checkIdsStr = "";
String judgeIdsStr = "";//djfndiosbchjdshjiowceduikmn String judgeIdsStr = "";
// 获取选择题、判断题、单选题的列表
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;
} }
@ -543,53 +499,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;
@ -600,22 +556,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());
@ -626,60 +582,58 @@ 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));
@ -687,6 +641,7 @@ public class ExamServiceImpl implements ExamService {
recordDetailVo.setAnswersRightMap(answersRightMap); recordDetailVo.setAnswersRightMap(answersRightMap);
return recordDetailVo; return recordDetailVo;
} }
/** /**
* - * -
* *
@ -695,7 +650,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);
} }
@ -717,4 +672,3 @@ public class ExamServiceImpl implements ExamService {
return replaceLastSeparator(sb.toString()); return replaceLastSeparator(sb.toString());
} }
} }
//注释完毕

@ -1,38 +1,24 @@
/***********************************************************
* @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;
import lombok.Data; import lombok.Data;
/**
* @Description: ,便JSON
* API,JSON
* Lombok@Datagettersetter
* Jackson@JsonPropertyJSON使
*/
@Data @Data
public class ExamCardVo { public class ExamCardVo {
/**
* ID
*/
@JsonProperty("id") @JsonProperty("id")
private String examId; private String examId;
/**
*
*/
@JsonProperty("title") @JsonProperty("title")
private String examName; private String examName;
/**
*
*/
@JsonProperty("avatar") @JsonProperty("avatar")
private String examAvatar; private String examAvatar;
/**
*
*/
@JsonProperty("content") @JsonProperty("content")
private String examDescription; private String examDescription;
/**
*
*/
@JsonProperty("score") @JsonProperty("score")
private Integer examScore; private Integer examScore;
/** /**

@ -6,24 +6,20 @@ 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,
@ -32,16 +28,12 @@ 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))
@ -49,29 +41,23 @@ 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') {
@ -86,7 +72,6 @@ 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
@ -106,14 +91,13 @@ 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'
@ -138,7 +122,6 @@ export default {
</Item> </Item>
) )
}, },
// 渲染子菜单
renderSubMenu (menu) { renderSubMenu (menu) {
const itemArr = [] const itemArr = []
if (!menu.hideChildrenInMenu) { if (!menu.hideChildrenInMenu) {
@ -154,7 +137,6 @@ export default {
</SubMenu> </SubMenu>
) )
}, },
// 渲染图标
renderIcon (icon) { renderIcon (icon) {
if (icon === 'none' || icon === undefined) { if (icon === 'none' || icon === undefined) {
return null return null

@ -7,9 +7,7 @@
* @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() !== ''))
} }
@ -17,17 +15,12 @@ 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)
@ -36,26 +29,18 @@ 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
}, '') }, '')
} }

@ -6,10 +6,8 @@
:confirmLoading="confirmLoading" :confirmLoading="confirmLoading"
:width="800" :width="800"
@cancel="cancelHandel"> @cancel="cancelHandel">
<!-- 使用a-row和a-col布局左边是裁剪框右边是预览框 -->
<a-row> <a-row>
<a-col :xs="24" :md="12" :style="{height: '350px'}"> <a-col :xs="24" :md="12" :style="{height: '350px'}">
<!-- 使用vue-cropper组件设置图片是否显示信息自动裁剪自动裁剪宽度自动裁剪高度固定框 -->
<vue-cropper <vue-cropper
ref="cropper" ref="cropper"
:img="options.img" :img="options.img"
@ -23,14 +21,12 @@
</vue-cropper> </vue-cropper>
</a-col> </a-col>
<a-col :xs="24" :md="12" :style="{height: '350px'}"> <a-col :xs="24" :md="12" :style="{height: '350px'}">
<!-- 预览框显示裁剪后的图片 -->
<div class="avatar-upload-preview"> <div class="avatar-upload-preview">
<img :src="previews.url" :style="previews.img"/> <img :src="previews.url" :style="previews.img"/>
</div> </div>
</a-col> </a-col>
</a-row> </a-row>
<!-- 底部按钮 -->
<template slot="footer"> <template slot="footer">
<a-button key="back" @click="cancelHandel"></a-button> <a-button key="back" @click="cancelHandel"></a-button>
<a-button key="submit" type="primary" :loading="confirmLoading" @click="okHandel"></a-button> <a-button key="submit" type="primary" :loading="confirmLoading" @click="okHandel"></a-button>
@ -48,18 +44,18 @@ export default {
*/ */
data () { data () {
return { return {
visible: false, // visible: false,
id: null, // id id: null,
confirmLoading: false, // confirmLoading: false,
options: { options: {
img: '/avatar2.jpg', // img: '/avatar2.jpg',
autoCrop: true, // autoCrop: true,
autoCropWidth: 200, // autoCropWidth: 200,
autoCropHeight: 200, // autoCropHeight: 200,
fixedBox: true // fixedBox: true
}, },
previews: {} // previews: {}
} }
}, },
methods: { methods: {

@ -1,33 +1,26 @@
<template> <template>
<div class="account-settings-info-view"> <div class="account-settings-info-view">
<!-- 使用a-row和a-col组件创建一个两列的布局 -->
<a-row :gutter="16"> <a-row :gutter="16">
<!-- 左侧列占据24/24的宽度在lg及以上屏幕上占据16/24的宽度 -->
<a-col :md="24" :lg="16"> <a-col :md="24" :lg="16">
<!-- 使用a-form组件创建一个垂直布局的表单 -->
<a-form layout="vertical"> <a-form layout="vertical">
<!-- 表单项用于输入昵称 -->
<a-form-item <a-form-item
label="昵称" label="昵称"
> >
<a-input placeholder="给自己起个名字" /> <a-input placeholder="给自己起个名字" />
</a-form-item> </a-form-item>
<!-- 表单项用于输入Bio -->
<a-form-item <a-form-item
label="Bio" label="Bio"
> >
<a-textarea rows="4" placeholder="You are not alone."/> <a-textarea rows="4" placeholder="You are not alone."/>
</a-form-item> </a-form-item>
<!-- 表单项用于输入电子邮件 -->
<a-form-item <a-form-item
label="电子邮件" label="电子邮件"
:required="false" :required="false"
> >
<a-input placeholder="exp@admin.com"/> <a-input placeholder="exp@admin.com"/>
</a-form-item> </a-form-item>
<!-- 表单项用于输入登录密码 -->
<a-form-item <a-form-item
label="登录密码" label="登录密码"
:required="false" :required="false"
@ -35,7 +28,6 @@
<a-input placeholder="密码"/> <a-input placeholder="密码"/>
</a-form-item> </a-form-item>
<!-- 表单项用于提交和保存按钮 -->
<a-form-item> <a-form-item>
<a-button type="primary">提交</a-button> <a-button type="primary">提交</a-button>
<a-button style="margin-left: 8px">保存</a-button> <a-button style="margin-left: 8px">保存</a-button>
@ -43,25 +35,18 @@
</a-form> </a-form>
</a-col> </a-col>
<!-- 右侧列占据24/24的宽度在lg及以上屏幕上占据8/24的宽度最小高度为180px -->
<a-col :md="24" :lg="8" :style="{ minHeight: '180px' }"> <a-col :md="24" :lg="8" :style="{ minHeight: '180px' }">
<!-- 使用ant-upload-preview组件创建一个头像预览框 -->
<div class="ant-upload-preview" @click="$refs.modal.edit(1)" > <div class="ant-upload-preview" @click="$refs.modal.edit(1)" >
<!-- 使用a-icon组件创建一个上传图标 -->
<a-icon type="cloud-upload-o" class="upload-icon"/> <a-icon type="cloud-upload-o" class="upload-icon"/>
<!-- 使用mask组件创建一个遮罩层 -->
<div class="mask"> <div class="mask">
<!-- 使用a-icon组件创建一个加号图标 -->
<a-icon type="plus" /> <a-icon type="plus" />
</div> </div>
<!-- 显示头像图片 -->
<img :src="option.img"/> <img :src="option.img"/>
</div> </div>
</a-col> </a-col>
</a-row> </a-row>
<!-- 使用avatar-modal组件创建一个头像模态框 -->
<avatar-modal ref="modal"> <avatar-modal ref="modal">
</avatar-modal> </avatar-modal>
@ -69,7 +54,6 @@
</template> </template>
<script> <script>
// AvatarModal
import AvatarModal from './AvatarModal' import AvatarModal from './AvatarModal'
export default { export default {
@ -81,26 +65,18 @@ export default {
// cropper // cropper
preview: {}, preview: {},
option: { option: {
//
img: '/avatar2.jpg', img: '/avatar2.jpg',
//
info: true, info: true,
//
size: 1, size: 1,
//
outputType: 'jpeg', outputType: 'jpeg',
//
canScale: false, canScale: false,
//
autoCrop: true, autoCrop: true,
// //
autoCropWidth: 180, autoCropWidth: 180,
autoCropHeight: 180, autoCropHeight: 180,
//
fixedBox: true, fixedBox: true,
// //
fixed: true, fixed: true,
//
fixedNumber: [1, 1] fixedNumber: [1, 1]
} }
} }

@ -1,14 +1,10 @@
<script> <script>
//
import { colorList } from '../../../components/SettingDrawer/settingConfig' import { colorList } from '../../../components/SettingDrawer/settingConfig'
// ant-design-vueswitchlistitem
import ASwitch from 'ant-design-vue/es/switch' import ASwitch from 'ant-design-vue/es/switch'
import AList from 'ant-design-vue/es/list' import AList from 'ant-design-vue/es/list'
import AListItem from 'ant-design-vue/es/list/Item' import AListItem from 'ant-design-vue/es/list/Item'
// mixin
import { mixin } from '../../../utils/mixin' import { mixin } from '../../../utils/mixin'
// Meta
const Meta = AListItem.Meta const Meta = AListItem.Meta
export default { export default {
@ -24,7 +20,6 @@ export default {
} }
}, },
filters: { filters: {
//
themeFilter (theme) { themeFilter (theme) {
const themeMap = { const themeMap = {
'dark': '暗色', 'dark': '暗色',
@ -34,13 +29,11 @@ export default {
} }
}, },
methods: { methods: {
//
colorFilter (color) { colorFilter (color) {
const c = colorList.filter(o => o.color === color)[0] const c = colorList.filter(o => o.color === color)[0]
return c && c.key return c && c.key
}, },
//
onChange (checked) { onChange (checked) {
if (checked) { if (checked) {
this.$store.dispatch('ToggleTheme', 'dark') this.$store.dispatch('ToggleTheme', 'dark')

@ -1,12 +1,8 @@
<template> <template>
<div class="page-header-index-wide"> <div class="page-header-index-wide">
<!-- 卡片组件用于展示内容 -->
<a-card :bordered="false" :bodyStyle="{ padding: '16px 0', height: '100%' }" :style="{ height: '100%' }"> <a-card :bordered="false" :bodyStyle="{ padding: '16px 0', height: '100%' }" :style="{ height: '100%' }">
<!-- 账户设置信息主容器 -->
<div class="account-settings-info-main" :class="device"> <div class="account-settings-info-main" :class="device">
<!-- 账户设置信息左侧 -->
<div class="account-settings-info-left"> <div class="account-settings-info-left">
<!-- 菜单组件用于展示导航 -->
<a-menu <a-menu
:mode="device == 'mobile' ? 'horizontal' : 'inline'" :mode="device == 'mobile' ? 'horizontal' : 'inline'"
:style="{ border: '0', width: device == 'mobile' ? '560px' : 'auto'}" :style="{ border: '0', width: device == 'mobile' ? '560px' : 'auto'}"
@ -14,28 +10,22 @@
type="inner" type="inner"
@openChange="onOpenChange" @openChange="onOpenChange"
> >
<!-- 菜单项用于展示导航链接 -->
<a-menu-item key="/account/settings/base"> <a-menu-item key="/account/settings/base">
<!-- 路由链接用于跳转到基本设置页面 -->
<router-link :to="{ name: 'BaseSettings' }"> <router-link :to="{ name: 'BaseSettings' }">
基本设置 基本设置
</router-link> </router-link>
</a-menu-item> </a-menu-item>
<a-menu-item key="/account/settings/custom"> <a-menu-item key="/account/settings/custom">
<!-- 路由链接用于跳转到个性化设置页面 -->
<router-link :to="{ name: 'CustomSettings' }"> <router-link :to="{ name: 'CustomSettings' }">
个性化 个性化
</router-link> </router-link>
</a-menu-item> </a-menu-item>
</a-menu> </a-menu>
</div> </div>
<!-- 账户设置信息右侧 -->
<div class="account-settings-info-right"> <div class="account-settings-info-right">
<!-- 账户设置信息标题 -->
<div class="account-settings-info-title"> <div class="account-settings-info-title">
<span>{{ $route.meta.title }}</span> <span>{{ $route.meta.title }}</span>
</div> </div>
<!-- 路由视图用于展示当前路由对应的组件 -->
<route-view></route-view> <route-view></route-view>
</div> </div>
</div> </div>

Loading…
Cancel
Save