在vue开发中问卷调查、答题类总结
说明
- 服务端返回的数据,以及需要提交给服务端的数据
- 具体思路
- 主要代码
一、服务端返回的数据,以及需要提交给服务端的数据:
- 服务端返回的数据:
//以下是服务端返回的试题列表数据
{
"data": [
{
"id": 13,
"type": 0,
"title": "题目1?",
"options": [
{
"id": 1,// option_id
"question_id": 13,
"content": "选项1",
"score": 0,//分值
"ended": 0,// 是否结束题(0 否, 1 是)
"jump_id": null // 试题跳转id 注意:选项优先于试题进行跳转,如果都没有跳转id则进入下一题
},
{
"id": 2,
"question_id": 13,
"content": "选项2",
"score": 0,
"ended": 0,
"jump_id": 16
},
{
"id": 16,
"question_id": 13,
"content": "选项3",
"score": 0,
"ended": 0,
"jump_id": 16
},
{
"id": 22,
"question_id": 13,
"content": "选项4",
"score": 0,
"ended": 0,
"jump_id": null
},
{
"id": 23,
"question_id": 13,
"content": "选项5",
"score": 0,
"ended": 0,
"jump_id": null
},
{
"id": 25,
"question_id": 13,
"content": "选项6",
"score": 0,
"ended": 0,
"jump_id": null
}
],
"hint": null, // 提示信息
"jump_id": null// 试题跳转id
},
{
"id": 17,
"type": 0,
"title": "题目2",
"options": [
{
"id": 32,
"question_id": 17,
"content": "选项1",
"score": 0,
"ended": 0,
"jump_id": 18
},
{
"id": 33,
"question_id": 17,
"content": "选项2",
"score": 2.5,
"ended": 0,
"jump_id": 18
},
{
"id": 34,
"question_id": 17,
"content": "选项3",
"score": 3.5,
"ended": 0,
"jump_id": 18
},
{
"id": 35,
"question_id": 17,
"content": "选项4",
"score": 4.5,
"ended": 0,
"jump_id": 18
}
],
"hint": null,
"jump_id": null
},
- 需要提交给服务端的数据:
"data": {
"list": [
{
"id": 17,
"type": 1,
"title": "题目1",
"options": [
{
"id": 32,
"question_id": 17,
"content": "选项1",
"score": 0,
"ended": 0,
"jump_id": 18,
"select": 0
},
{
"id": 33,
"question_id": 17,
"content": "选项2",
"score": 2.5,
"ended": 0,
"jump_id": 18,
"select": 0
},
{
"id": 34,
"question_id": 17,
"content": "选项3",
"score": 3.5,
"ended": 0,
"jump_id": 18,
"select": 1
},
{
"id": 35,
"question_id": 17,
"content": "选项4",
"score": 4.5,
"ended": 0,
"jump_id": 18,
"select": 1
}
],
"hint": null,
"jump_id": null
},
{
"id": 18,
"type": 0,
"title": "题目2",
"options": [
{
"id": 36,
"question_id": 18,
"content": "选项1",
"score": 0,
"ended": 0,
"jump_id": null,
"select": 0
},
{
"id": 37,
"question_id": 18,
"content": "选项2",
"score": 1.76,
"ended": 0,
"jump_id": null,
"select": 0
},
{
"id": 38,
"question_id": 18,
"content": "选项3",
"score": 5.27,
"ended": 0,
"jump_id": null,
"select": 1
},
{
"id": 39,
"question_id": 18,
"content": "选项4",
"score": 2.64,
"ended": 0,
"jump_id": null,
"select": 1
}
],
"hint": "题目注释",
"jump_id": 17
}
],
"age": 21
}
二、具体思路
1. 请求接口获取试题列表,并创建一个数组(list)用于最后的提交。
2. 判断第一题的类型(单、双选)并渲染。
3. 选择选项,在选中的选项中加入选中(select)属性。同时将该题(包含选项)添加进list。
4. 点击提交按钮,进行判断:
- 判断是否选择了选项:是->继续判断;否->进行提示。
- 判断选项中的ended(是否结束):0->继续判断;1->结束答题。
- 判断选项中的jump_id(跳转题目):null->继续判断;!null->跳转到题目id为jump_id的题目。
- 判断题目中的jump_id(跳转题目):null->跳转到当前题目索引的下一题; !null->跳转到题目id为jump_id的题目。
5. 结束答题时,将list进行提交
三、主要代码
<template>
<div class="exposure-rating">
<header class="top-title" style="color: #fff">
<h5>风险评估</h5>
</header>
<div class="container">
<div class="container-wrap">
<!-- 题目 start -->
<div class="container-wrap-title">
{{ SelectType[showTopic.type] }}
</div>
<div class="container-wrap-topic">
{{ showTopic.title }}
<span v-if="showTopic.hint">(*{{ showTopic.hint }})</span>
</div>
<!-- 题目 end -->
<!-- 单选模式渲染的试题选项 start -->
<van-radio-group
v-model="radio"
v-if="!showTopic.type"
icon-size="17px"
checked-color="#ffa135"
class="container-wrap-elect"
>
<van-radio
:name="index"
v-for="(item, index) in showTopic.options"
:key="index"
@click="choice(item)"
>{{ item.content }}
</van-radio>
</van-radio-group>
<!-- 单选模式渲染的试题选项 end -->
<!-- 多选模式渲染的试题选项 start -->
<van-checkbox-group
v-model="result"
:max="0"
class="container-wrap-elect"
icon-size="17px"
checked-color="#ffa135"
v-if="showTopic.type"
>
<van-checkbox
:name="index"
v-for="(item, index) in showTopic.options"
:key="index"
@click="choice(item)"
>{{ item.content }}</van-checkbox
>
</van-checkbox-group>
<!-- 多选模式渲染的试题选项 end -->
</div>
</div>
<!-- 提交 start -->
<footer>
<van-button
round
type="info"
class="submit"
color="#6a74ef"
@click="submit"
:disabled="isdisabled"
>下 一 题</van-button
>
</footer>
<!-- 提交 end -->
</div>
</template>
<script>
import { ApiModel } from "../../assets/js/request/api";
import { Toast } from "vant";
const apimodel = new ApiModel();
export default {
data() {
return {
pullList: [], //请求获取的试题列表
submitList: [], //最后提交需要的试题列表
showTopic: {}, //渲染的试题
index: 0, //题目索引
radio: [], //单选
result: [], //多选
SelectType: {
0: "单选",
1: "多选",
},
jump_id: null, //选项跳转id
ended: null, //是否结束答题
isdisabled: false, //是否禁止答题
};
},
mounted() {
this.GetList(); //获取试题列表
},
methods: {
// 1、获取试题列表
GetList() {
apimodel.getQuestionLists().then(
(res) => {
this.pullList = res.data.data; //获取到试题列表
this.getTopic(); //渲染试题
},
(err) => {
console.log(err, "错误原因");
}
);
},
// 2、渲染试题
getTopic() {
this.showTopic = this.pullList[this.index]; //获取渲染的试题
this.result = []; //清空选项
this.radio = [];
console.log(
"题目跳转id:",
this.pullList[this.index].jump_id,
"索引:",
this.index
);
},
// 3、选择选项
choice(item) {
/* 试题为单选 */
if (this.showTopic.type == 0) {
this.showTopic.options.map((item1) => {
item1.select = 0;
});
item.select = 1;
this.ended = item.ended; //是否结束答题
this.jump_id = item.jump_id; //选项跳转id
console.log(
"(单选)",
"是否结束答题:",
this.ended,
"选项跳转id:",
this.jump_id
);
return;
}
/* 试题为多选 */
if (this.showTopic.type == 1) {
item.select = !item.select;
if (item.select) {
item.select = 1;
} else {
item.select = 0;
}
//过滤出有jump_id的选项
let arry = this.showTopic.options.filter((item) => {
return item.jump_id !== null;
});
//选项跳转id
this.jump_id = arry[0].jump_id;
//过滤出有ended的选项
let arry1 = this.showTopic.options.filter((item) => {
return item.ended !== null;
});
//是否结束答题
this.ended = arry1[0].jump_id;
console.log(
"(多选)",
"是否结束答题:",
this.ended,
"选项跳转id:",
this.jump_id
);
return;
}
},
// 4、提交
submit() {
let select = {
isSingle: this.radio.length, //单选
unSingle: this.result.length, //多选
isEnd: this.ended, //是否结束答题
jump_id: this.jump_id, //选项跳转id
jumpId: this.showTopic.jump_id, //题目跳转id
joinList: this.submitList.push(this.showTopic), //加入最后提交需要的试题列表
};
// 4.1、判断是否选择选项
if (select.isSingle == 0 && select.unSingle == 0) {
Toast.fail("请选择选项!");
return;
}
// 4.2、判断是否结束答题
if (select.isEnd) {
select.joinList;
this.getSubmit(); //提交
return;
}
// 4.3、判断选项跳转id
if (select.jump_id) {
console.log("根据选项跳转");
this.index = this.pullList.findIndex((item) => {
return item.id == select.jump_id;
});
this.getTopic();
return;
}
// 4.4、判断题目跳转id
if (select.jumpId) {
console.log("根据题目跳转");
this.index = this.pullList.findIndex((item) => {
return item.id == select.jumpId;
});
this.getTopic();
return;
}
//4.5、根据题目索引跳转
if (select.jump_id == null && select.jumpId == null) {
console.log("根据题目索引跳转");
let indexed = this.pullList.findIndex((item) => {
return item.id == this.showTopic.id;
});
this.index = indexed + 1;
this.getTopic();
return;
}
},
// 提交请求
getSubmit() {
this.isdisabled = true;
let additional = JSON.parse(this.$route.query.additional);
let data = {
data: {
list: this.submitList,
additional: additional,
},
};
apimodel.postAddRiskRecord(data).then(
(res) => {
let resultStatus = JSON.stringify(res.data.result_snapshot);
window.sessionStorage.setItem("resultStatus", resultStatus);
Toast.success("完成测试!");
setTimeout(() => {
this.$router.push({
path: "/riskDetail",
query: {
fromRating: "1",
},
});
}, 1500);
},
(err) => {
console.log(err, "返回错误");
Toast.fail(err.data.message);
}
);
},
},
};
</script>
<style lang="scss" scoped>
.exposure-rating {
position: relative;
background-image: linear-gradient(to right, #4a66da, #a2abe0);
height: 100vh;
.container {
position: relative;
width: 352px;
height: 230px;
margin: 20px auto 0;
.container-wrap {
position: absolute;
z-index: 99;
top: 10px;
width: 322px;
margin: 20px auto 0;
padding: 10px 15px;
border-radius: 10px;
background-color: #fff;
box-shadow: 0px 4px 14px 1px rgba(89, 103, 232, 0.12);
.container-wrap-title {
position: absolute;
top: -7px;
left: 15px;
text-align: center;
line-height: 36px;
width: 36px;
height: 36px;
color: #fff;
font-size: 13px;
background-image: url("../../assets/img/risk-choice-bg.png");
background-size: cover;
}
.container-wrap-topic {
font-size: 20px;
line-height: 28px;
color: #222;
margin-top: 46px;
span {
color: red;
font-size: 12px;
line-height: 12px;
}
}
.container-wrap-elect {
margin: 10px 0;
font-size: 17px;
div {
margin: 20px 0 !important;
}
}
}
}
footer {
position: absolute;
bottom: 0;
background-color: #f2f3ff;
height: 440px;
width: 100%;
.submit {
position: fixed;
bottom: 5%;
width: 80%;
left: 10%;
}
}
}
</style>