登录页面设计
登录页面设计思路-分为三个角色进行登录,分别为学生,教师,管理员。
前端将登录设计为表单形式,通过选项组件绑定角色参数,向后端传递角色信息,通过表单绑定向后端传递登录者所有信息
<div style="display: flex; gap: 20px;">
<vs-radio color="rgb(59,222,200)" v-model="form.type" val="学生">
学生
</vs-radio>
<vs-radio v-model="form.type" val="教师">
教师
</vs-radio>
<vs-radio danger v-model="form.type" val="管理员">
管理员
</vs-radio>
</div>
@PostMapping("/user/login")
public Map<String,Object> Login(@RequestBody User user){
Map<String,Object> map = new HashMap<>();
User u = userService.LoginByUserName(user.getUserNumber());
Map<String,String>payload = new HashMap<>();
if(u!=null){
if(user.getPassword().equals(u.getPassword()) && user.getType().equals(u.getType())){
if (u.getType().equals("学生")){
String className = userService.FindClassNameByClassId(u.getClassid());
map.put("className",className);
}
payload.put("id",u.getId().toString());
payload.put("username",u.getUserNumber());
String token = JWTUtil.createToken(payload);
System.out.println("token为"+token);
map.put("UserInfo",u);
map.put("userId",u.getId());
map.put("code",200);
map.put("status",token);
map.put("msg","登陆成功");
}
else {
map.put("msg","密码错误");
map.put("status",0);
}
}
else{
map.put("msg","不存在该用户");
map.put("status",0);
}
return map;
}
通过在数据库中存入type字段,实现与后台对接并实现特定角色登录
考试系统设计
附:一张设计手稿,随笔字丑请忽略
设计思路(可结合下面数据表进行理解):
1.试卷表:每一张试卷都对应一个特有的PaperId,并且在表中存有PaperName(试卷名),PaperTime(考试时间),PaperImageSrc(考试封面图),后续可以自信添加字段,丰富考卷所具有的信息。
2.题目表:每一道题目都有一个PaperId,可以以此将隶属与对应试卷的题目信息读取,每一道题目含有独有的QuestionId(题目ID),QuestionContent(题目内容),QuestionScore(题目的得分,可以通过组卷时设置对应分数,实现灵活组卷),QuestionType(题目类型),通过这个字段可以定义题目对应的不同类型。
3.题目细节表:每一条数据都有一个独有的QuestionId,可以让它属于对应的题目,QuesitonOption(题目选项表,设置ABCD等类型的选项内容),可以通过读取对应细节有几条数据来设置它为单选题还是填空题,QuestionCorrect(选项是否正确),通过此字段判断选项正确与否。
4.题目商店表:用于老师的组卷功能,QuestionId,QuestionContent,QuestionType,QuestionTheme(问题主题,方便用于搜索,但是VueSax搜索不需要后端数据即可实现)。
思路串联:
一、用户对应考卷的设计:通过UserNumber字段从f_exam_userneedexam表中查询该用户对应的所有PaperId,然后通过此PaperId查询f_exam_paper表中考卷具体信息,即可展示用户对应所需的考试信息。
二、考卷的设计:一张试卷对应独特的PaperId,一道题目衔接对应的PaperId(衔接试卷表),题目选项衔接对应的QuestionId(衔接题目表)。
//把试卷组好
@GetMapping("/exam/SelectAllQustionByPaperIdUpdate")
public List<QuestionWithOptions> SelectAllQustionByPaperIdUpdate(@RequestParam Integer PaperId){
List<QuestionWithOptions> questionsWithOptions = new ArrayList<>();
List<Questions> allQuestions = userExamService.SelectAllQustionByPaperIdUpdate(PaperId);
for (Questions question : allQuestions) {
List<Options> options = userExamService.SelectAllQustionByQuestionId(question.getQuestionId());
QuestionWithOptions questionWithOptions = new QuestionWithOptions(question, options);
questionsWithOptions.add(questionWithOptions);
}
// System.out.println("第一组数据测试获取问题列表"+questionsWithOptions.get(0).getQuestion());
// System.out.println("第一组数据测试获取选项列表"+questionsWithOptions.get(0).getOptions());
// System.out.println("第一组数据测试获取选项列表的第一个选项内容"+questionsWithOptions.get(0).getOptions().get(0));
// System.out.println("第一组数据测试获取选项列表的第二个选项内容"+questionsWithOptions.get(0).getOptions().get(1));
// System.out.println("第一组数据"+questionsWithOptions.get(0));
// System.out.println("返回的最终数据"+questionsWithOptions);
return questionsWithOptions;
}
@Data
public class QuestionWithOptions {
private Questions question;
private List<Options> options;
}
<vs-dialog scroll overflow-hidden auto-width blur not-close :prevent-close="true" full-screen v-model="ExamActive">
<div>
<h1>考卷</h1>
<div v-for="(questionWithOptions, index) in examQuestions" :key="index">
<h2>{{ questionWithOptions.question.questionContent }}</h2>
<div v-for="(option, i) in questionWithOptions.options" :key="i">
<label>
<!-- <vs-checkbox :value="option" v-model="selectedOptions[index]">-->
<!-- {{ option.questionOption }}-->
<!-- </vs-checkbox>-->
<input type="radio" :value="option" v-model="selectedOptions[index]">
{{ option.questionOption }}
</label>
</div>
</div>
<vs-button gradient @click="submitExam">提交</vs-button>
</div>
</vs-dialog>
export default {
data(){
return{
UserNumber:"",
UserName:"",
examInfo:[],
active: false,
input1: '',
input2: '',
checkbox1: false,
ExamActive: false,
examQuestions: [], // 包含问题和选项的数组
selectedOptions: [], // 用户选择的答案
// JSON格式理解
//
// 数组和对象
// LJL:[ ExamRecord:{
// PaperId: "",
// ExamUserNumber: "",
// ExamUserName: "",
// },, ExamRecord1:{
// PaperId: "",
// ExamUserNumber: "",
// ExamUserName: "",
// },]
ExamRecord:{
paperId: "",
examUserNumber: "",
examUserName: "",
},
UserAnswer:{
Answers:"",
UserNumber:"",
UserName:"",
PaperId:"",
},
PaperId:""
}
},
methods:{
StartExam(){
this.active = !this.active;
this.ExamActive = !this.ExamActive;
this.ExamRecord = {
paperId: this.PaperId,
examUserNumber: this.UserNumber,
examUserName: this.UserName
};
//插入开考记录
this.$ExamApi.insertRecordFromStartExam(this.ExamRecord).then(res=>{
console.log(this.ExamRecord)
}).catch(err=>console.log(err))
},
SelectExamByPaperId(paperId) {
this.active = !this.active
this.PaperId = paperId
this.$ExamApi.SelectAllQustionByPaperIdUpdate(paperId).then(res=>{
this.examQuestions = res.data
console.log(res.data)
// 初始化选项
this.selectedOptions = new Array(this.examQuestions.length).fill("");
console.log(this.selectedOptions)
}).catch(err=>console.log(err))
// 这里可以根据 paperId 执行你需要的逻辑,比如打开对应考试的详情页面等
},
submitExam() {
this.UserAnswer={
Answers: this.selectedOptions,
UserName: this.UserName,
UserNumber: this.UserNumber,
PaperId: this.PaperId
}
this.$ExamApi.insertUserAnswerAndSubmitExamToAddScore(this.UserAnswer).then(res=>{
console.log(this.UserAnswer)
this.openNotification('top-center', '#7d33ff', `<i class='bx bx-bell' ></i>`)
this.ExamActive = !this.ExamActive
})
// 这里可以将用户的答案发送给后端进行处理
},
//获取当前用户所需要的考试信息
UserNeedExamByUserNumber(){
// this.$loginApi.UserLogin(this.loginData).then(res=>{
this.$ExamApi.UserNeedExamByUserNumber(this.UserNumber).then(res=>{
this.examInfo = res.data.dataobject
console.log("查询到的考试信息为")
console.log(this.examInfo)
}).catch(err=>console.log(err))
},
getCoverUrl(coverUrl) {
return this.$config.getBaseUrl()+coverUrl;
},
//消息通知框
openNotification(position = null, color, icon) {
const noti = this.$vs.notification({
icon,
color,
position,
title: '恭喜您!,顺利完成了测试!',
text: `您将可以在考试查询界面,查询到自己的成绩以及答题情况!!!`
})
}
},
mounted() {
this.UserNumber = sessionStorage.getItem("userNumber");
this.UserName = sessionStorage.getItem("userName");
this.UserNeedExamByUserNumber();
}
}
三、点击开考的设计:向f_exam_record(考试记录表)中插入,考试人员信息(ExamUserNumber,ExamUserName),开考时间(ExamStartTime),对应试卷PaperId。此时每条数据对应的ExamScore和ExamEndTime为空,通过交卷执行Update操作进行记录。
四、点击交卷的设计:
将用户所选的选项进行遍历,分别插入f_exam_user_answer(用户答题内容表,用于查看用户答题具体情况,即生成一份用户答题内容卷),记录用户所答题的具体信息。
通过以下代码获取此用户所作的卷子记录(通过用户学号,开考时间的降序排序,限制为一条数据,获取用户当前所考的最新试卷,用于插入交卷时间和总分)
<!-- 获得记录Id-->
<select id="SelectRecordId" parameterType="String" resultType="Integer">
SELECT * from f_exam_record where ExamUserNumber = #{ExamUserNumber} ORDER BY ExamStartTime DESC LIMIT 1
</select>
通过遍历questionCorrect字段,以获取哪条记录为正确选项,如果questionCorrect为true,通过此记录的QuestionId和PaperId在f_exam_question表中查找此题对应的QuestionScore值,然后在此时定义Score对象进行计算总分(避免了异步冲突),然后将总分以及交卷时间插入记录表格。
@PostMapping("/exam/insertUserAnswerAndSubmitExamToAddScore")
public void insertUserAnswer(@RequestBody Map<String, Object> requestData) {
List<Map<String, Object>> answersMapList = (List<Map<String, Object>>) requestData.get("Answers");
String userName = (String) requestData.get("UserName");
String userNumber = (String) requestData.get("UserNumber");
Integer recordId = userExamService.SelectRecordId(userNumber);
Integer PaperId = (Integer) requestData.get("PaperId");
int score = 0;
for (Map<String, Object> answerMap : answersMapList) {
UserAnswer userAnswer = new UserAnswer();
userAnswer.setId((int) answerMap.get("id"));
userAnswer.setQuestionId((int) answerMap.get("questionId"));
userAnswer.setQuestionOption((String) answerMap.get("questionOption"));
userAnswer.setQuestionCorrect((boolean) answerMap.get("questionCorrect"));
userAnswer.setExamUserNumber(userNumber);
userAnswer.setExamUserName(userName);
userAnswer.setRecordId(recordId);
userExamService.insertUserAnswer(userAnswer);
if((Boolean) answerMap.get("questionCorrect")==true){
ExamRequestScore examRequestScore = new ExamRequestScore();
examRequestScore.setPaperId(PaperId);
examRequestScore.setQuestionId(userAnswer.getQuestionId());
Integer s = userExamService.selectScoreFromStoreByQuestionIdAndPaperId(examRequestScore);
score = s+score;
System.out.println("编号为"+userAnswer.getQuestionId()+"的问题回答正确"+"并且正确答案的分数为:"+s);
System.out.println("总分为"+score);
}
}
ExamRecord examRecord = new ExamRecord();
examRecord.setPaperId(PaperId);
examRecord.setExamUserNumber(userNumber);
examRecord.setExamScore(score);
System.out.println("examRecord"+examRecord);
userExamService.updateRecordFromEndExam(examRecord);
}