vue+elementUI问卷调研,支持新增题目,修改题目,题目上移下移,新增选项,选项上移下移,题目跳转功能,支持预览
<template>
<div class="app-container">
<el-card shadow="never">
<el-row :gutter="20" type="flex" justify="space-between">
<el-col :span="12" style="display: flex;align-items: center;">
<div style="margin-right: 30px;">科室:{{ baseForm.title }}</div>
<el-button type="primary" @click="handleAddTopic">增加题目</el-button>
</el-col>
<el-col :span="12" style="display: flex;align-items: center;">
<div style="margin-right: 30px;">
<span>状态:</span>
<el-radio
v-model="baseForm.enable"
:label="true"
border
size="medium"
>启用</el-radio
>
<el-radio
v-model="baseForm.enable"
:label="false"
border
size="medium"
>禁用</el-radio
>
</div>
<el-button @click="handlePreview" type="primary" style="margin-right: 30px;"
>保存并预览</el-button
>
<el-button
type="primary"
style="margin-right: 30px;"
@click="handleSubmit"
>保 存</el-button
>
</el-col>
</el-row>
</el-card>
<el-form
:model="baseForm"
ref="baseForm"
label-width="100px"
class="demo-dynamic"
>
<div v-for="(item, index) in baseForm.questions" :key="index">
<el-card shadow="never" style="margin-top: 20px;">
<el-form-item :label="`第${index + 1}题`">
<el-button type="primary" @click="handleMoveUpTopic(index)"
>上移</el-button
>
<el-button type="primary" @click="handleMoveDownTopic(index)"
>下移</el-button
>
<el-button type="danger" @click="handleDelTopic(index, item)"
>删除</el-button
>
</el-form-item>
<el-row>
<el-col :span="8">
<el-form-item
:prop="'questions.' + index + '.question'"
label="标题"
:rules="[
{
required: true,
message: '请输入标题',
trigger: 'blur'
}
]"
>
<el-input
v-model="item.question"
type="textarea"
maxlength="64"
show-word-limit
style="width: 400px;"
></el-input>
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item
:prop="'questions.' + index + '.questionType'"
label="题型"
:rules="[
{
required: true,
message: '请选择题型',
trigger: 'change'
}
]"
>
<el-radio-group v-model="item.questionType" @input="handleQuestionType">
<el-radio label="SINGLE">单选题</el-radio>
<el-radio label="MULTI">多选题</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<div v-for="(itemA, indexA) in item.answers">
<el-row type="flex">
<el-form-item
:key="indexA"
:label="`选项${indexA + 1}`"
:rules="{
required: true,
message: '选项不能为空',
trigger: 'blur'
}"
>
<el-input
v-model="item.answers[indexA].answer"
maxlength="64"
show-word-limit
style="width: 400px;"
></el-input>
<el-button
type="primary"
plain
@click="handleMoveUpOption(index, indexA)"
>上移</el-button
>
<el-button
type="primary"
plain
@click="handleMoveDownOption(index, indexA)"
>下移</el-button
>
<el-button
type="danger"
plain
@click="handleDelOption(index, indexA, itemA)"
>删除</el-button
>
</el-form-item>
<el-form-item prop="motifQuestionId" label="题目跳转" v-if="item.questionType == 'SINGLE'">
<el-tooltip
content="设置选项跳转指定题目,未设置时默认跳转下一题,如需实现题目跳转关联请所有选项都关联同一题"
placement="top"
>
<i class="el-icon-warning"></i>
</el-tooltip>
<el-select
v-model="item.answers[indexA].subproblemQuestionId"
placeholder="请选择"
style="width: 200px;"
clearable
:disabled="baseForm.questions.length - 1 == index"
@focus="handleMotifQuestionFocus(index)"
>
<el-option
v-for="(item, j) in questionsListNew"
:key="j"
:label="item.question"
:value="item.questionId"
:disabled="item.disabled"
>
</el-option>
</el-select>
</el-form-item>
</el-row>
</div>
<el-form-item>
<el-button type="primary" plain @click="handleAddOption(index)"
>新增选项</el-button
>
</el-form-item>
</el-card>
</div>
</el-form>
<preview ref="preview" :dialogVisible="dialogVisible" :questionnaireId="baseForm.questionnaireId" @close="close"></preview>
</div>
</template>
<script>
import {
questionnaireInfoApi,
questionnaireUpdateApi,
questionnaireDeleteApi,
questionnaireAnswerDeleteApi
} from "@/api/hospital/department";
import preview from "./preview.vue";
export default {
name: "diseaseInvestigationEdit",
components:{preview},
data() {
return {
dialogVisible:false,
motifQuestionIdList: [],
questionsList: [],
questionsListNew: [],
baseForm: {
enable: true,
questionnaireId: null,
questions: [
{
question: "",
questionType: "SINGLE",
motifQuestionId: null,
answers: [
{
answer: ""
}
]
}
]
}
};
},
created() {
console.log(this.$route.query.questionnaireId);
if (this.$route.query.questionnaireId) {
this.baseForm.questionnaireId = this.$route.query.questionnaireId;
}
this.getDetails();
},
watch: {
"baseForm.questions": {
handler(newValue, oldValue) {
// 处理值变化
this.questionsList = newValue;
console.log(this.questionsList, "监听题目变化");
this.questionsListNew = this.questionsList;
},
deep: true,
immediate: true
}
},
methods: {
handleMotifQuestionFocus(index) {
this.questionsListNew = [];
this.questionsList.forEach((obj, indexA) => {
if (indexA <= index) {
obj.disabled = true;
} else {
obj.disabled = false;
}
});
this.questionsListNew = this.questionsList;
console.log(this.questionsListNew);
},
// 获取详情
getDetails() {
questionnaireInfoApi({
questionnaireId: this.baseForm.questionnaireId
}).then(res => {
this.baseForm = res.data;
for (var i of this.baseForm.questions) {
i.disabled = false;
}
});
},
// 新增选项
handleAddOption(index) {
this.baseForm.questions[index].answers.push({
answer: "",
subproblemQuestionIndex: null,
subproblemQuestionId: null
});
},
// 删除选项
handleDelOption(index, indexA, itemA) {
if (this.baseForm.questions[index].answers.length == 1) {
this.$message.warning("至少保留一条选项");
return;
} else {
if (itemA.answerId) {
this.$confirm("此操作将永久删除该选项, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
questionnaireAnswerDeleteApi([itemA.answerId])
.then(res => {
this.$message.success(res.message);
this.baseForm.questions[index].answers.splice(indexA, 1);
this.getDetails();
})
.catch(err => {
this.$message.error(err.message);
});
})
.catch(() => {});
} else {
this.baseForm.questions[index].answers.splice(indexA, 1);
}
}
},
// 选项上移
handleMoveUpOption(index, indexA) {
console.log(indexA);
if (indexA == 0) {
this.$message.warning("已经在第一条了");
return;
}
let optionList = this.baseForm.questions[index].answers;
optionList.splice(
indexA - 1,
1,
...optionList.splice(indexA, 1, optionList[indexA - 1])
);
},
// 选项下移
handleMoveDownOption(index, indexA) {
let optionList = this.baseForm.questions[index].answers;
optionList.splice(
indexA,
1,
...optionList.splice(indexA + 1, 1, optionList[indexA])
);
},
// 新增题目
handleAddTopic() {
this.baseForm.questions.push({
disabled: false,
question: "",
questionType: "SINGLE",
motifQuestionId: null,
answers: [
{
answer: "",
subproblemQuestionIndex: null,
subproblemQuestionId: null
}
]
});
},
// 题目上移
handleMoveUpTopic(index) {
if (index == 0) {
this.$message.warning("已经在第一条了");
return;
}
let topicList = this.baseForm.questions;
topicList.splice(
index - 1,
1,
...topicList.splice(index, 1, topicList[index - 1])
);
},
// 题目下移
handleMoveDownTopic(index) {
for (var i of this.baseForm.questions[index].answers) {
i.subproblemQuestionIndex = null;
i.subproblemQuestionId = null;
}
let topicList = this.baseForm.questions;
topicList.splice(
index,
1,
...topicList.splice(index + 1, 1, topicList[index])
);
},
// 删除题目
handleDelTopic(index, item) {
if (this.baseForm.questions.length == 1) {
this.$message.warning("至少保留一条题目");
return;
} else {
if (item.questionId) {
this.$confirm("此操作将永久删除该题目, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
questionnaireDeleteApi([item.questionId])
.then(res => {
this.$message.success(res.message);
this.baseForm.questions.splice(index, 1);
this.getDetails();
})
.catch(err => {
this.$message.error(err.message);
});
})
.catch(() => {});
} else {
this.baseForm.questions.splice(index, 1);
}
}
},
// 提交
handleSubmit() {
console.log(this.baseForm);
this.$refs["baseForm"].validate(valid => {
if (valid) {
questionnaireUpdateApi(this.baseForm)
.then(res => {
this.$message.success(res.message);
this.getDetails();
})
.catch(err => {
this.$message.error(err.message);
});
} else {
return false;
}
});
},
// 保存预览
handlePreview(){
this.$refs["baseForm"].validate(valid => {
if (valid) {
questionnaireUpdateApi(this.baseForm)
.then(res => {
this.$message.success(res.message);
this.getDetails();
this.dialogVisible = true
this.$refs.preview.questionsArr = []
this.$refs.preview.getDetails()
})
.catch(err => {
this.$message.error(err.message);
});
} else {
return false;
}
});
},
close(){
this.dialogVisible = false
},
handleQuestionType(val){
console.log(val)
}
}
};
</script>
<style lang="scss"></style>
预览功能preview.vue
<template>
<div>
<el-dialog
title="预览"
:visible.sync="dialogVisible"
width="30%"
:before-close="handleClose"
>
<div class="upDownBtn">
<div>
<el-button type="primary" icon="el-icon-arrow-up" circle @click="handleScrollTop"></el-button>
</div>
<div>
<el-button type="primary" icon="el-icon-arrow-down" circle style="margin-top: 10px;" @click="handleScrollBottom"></el-button>
</div>
</div>
<div class="container" ref="scrollDiv">
<div class="list">
<div class="headImg"></div>
<div class="content">
你好,我将咨询您一系列问题,请如实回答,以帮助我更快做出诊断
</div>
</div>
<div v-for="(item, index) in questionsArr" :key="index">
<!-- 单选 -->
<div class="list" v-if="item.questionType == 'SINGLE'">
<div class="headImg"></div>
<div class="question">
<div class="title">{{ item.question }}</div>
<div
class="option"
v-for="(itemA, indexA) in item.answers"
:key="indexA"
@click="handleCheckSingleAnswer(itemA, indexA, item, index)"
:class="{
singleChecked: itemA.answerId == item.answerCheckId,
disSelect: item.disSelect
}"
>
{{ itemA.answer }}
</div>
</div>
</div>
<!-- 多选 -->
<div class="list" v-if="item.questionType == 'MULTI'">
<div class="headImg"></div>
<div class="question">
<div class="title">
{{ item.question + "(多选)" }}
</div>
<div
class="option"
v-for="(itemB, indexB) in item.answers"
:key="indexB"
@click="handleCheckMultiAnswer(itemB, indexB, item, index)"
:class="{
singleChecked: itemB.check == true,
disSelect: item.disSelect
}"
>
{{ itemB.answer }}
</div>
<div
class="check"
@click="handleCheckMulti(item, index)"
:class="{ disSelectBtn: item.disSelect }"
>
选好了
</div>
</div>
</div>
</div>
</div>
</el-dialog>
</div>
</template>
<script>
import { questionnaireInfoApi } from "@/api/hospital/department";
export default {
props: {
dialogVisible: {
type: Boolean,
default: false
},
questionnaireId: {
type: String,
default: ""
}
},
data() {
return {
baseForm: {},
questionsArr: [],
questionIndex: null
};
},
methods: {
// 滚动到顶部
handleScrollTop() {
this.$nextTick(() => {
let scrollElem = this.$refs.scrollDiv;
scrollElem.scrollTo({ top: 0, behavior: "smooth" });
});
},
// 滚动到底部
handleScrollBottom() {
this.$nextTick(() => {
let scrollElem = this.$refs.scrollDiv;
scrollElem.scrollTo({
top: scrollElem.scrollHeight,
behavior: "smooth"
});
});
},
handleClose() {
this.$emit("close");
},
// 获取详情
getDetails() {
questionnaireInfoApi({
questionnaireId: this.questionnaireId
}).then(res => {
this.baseForm = res.data;
this.baseForm.questions.forEach(val => {
val.answerCheckId = "";
if (val.questionType == "MULTI") {
val.answers.forEach(e => {
e.check = false;
});
}
});
this.questionsArr.push(this.baseForm.questions[0]);
console.log(this.questionsArr);
});
},
// 单选
handleCheckSingleAnswer(itemA, indexA, item, index) {
console.log(itemA, indexA, item, index);
item.answerCheckId = itemA.answerId;
item.disSelect = true;
this.$set(this.questionsArr, index, item); //关键代码,当数组数据发生变化时,页面中动态绑定的样式没有变化
// 判断跳题
if (itemA.subproblemQuestionId) {
var obj = this.baseForm.questions.find(function(item) {
return item.questionId == itemA.subproblemQuestionId;
});
this.questionIndex = this.baseForm.questions.findIndex(
i => i.questionId == obj.questionId
);
this.questionsArr.push(obj);
} else {
if (this.questionIndex + 1 >= this.baseForm.questions.length) {
console.log("最后一道题了");
this.$message({
message: "恭喜你,已成功做完本次调研",
type: "success"
});
} else {
this.questionIndex += 1;
this.questionsArr.push(this.baseForm.questions[this.questionIndex]);
this.handleScrollBottom();
}
}
console.log(this.questionIndex, this.baseForm.questions.length);
},
// 多选
handleCheckMultiAnswer(itemB, indexB, item, index) {
itemB.check = !itemB.check;
this.$set(this.questionsArr, index, item);
},
// 多选选好了
handleCheckMulti(item, index) {
console.log(item)
var isCheck = item.answers.some(function(e) {
return e.check;
});
console.log(isCheck)
if(isCheck == false){
this.$message({
message: "请至少选择一个选项",
type: "warning"
});
return
}
item.disSelect = true;
this.questionIndex = this.baseForm.questions.findIndex(
i => i.questionId == item.questionId
);
console.log(this.questionIndex);
if (this.questionIndex + 1 >= this.baseForm.questions.length) {
console.log("最后一道题了");
this.$message({
message: "恭喜你,已成功做完本次调研",
type: "success"
});
} else {
this.questionIndex += 1;
this.questionsArr.push(this.baseForm.questions[this.questionIndex]);
this.handleScrollBottom();
}
}
}
};
</script>
<style lang="scss" scoped>
.container {
width: 375px;
height: 720px;
border: 1px solid #ccc;
margin: 0 auto;
padding: 12px;
overflow-y: scroll;
border-radius: 6px;
.list {
display: flex;
margin-bottom: 12px;
}
.headImg {
width: 39px;
height: 39px;
background: #d8d8d8;
border-radius: 8px;
margin-right: 9px;
}
.content {
flex: 1;
background: #f0f4f8;
border-radius: 0px 19px 19px 19px;
padding: 10px 15px;
font-size: 15px;
}
.question {
flex: 1;
background: #f0f4f8;
border-radius: 0px 19px 19px 19px;
padding: 20px;
.title {
font-size: 16px;
font-weight: 600;
color: #191b21;
margin-bottom: 16px;
}
.option {
width: 100%;
background: rgba(255, 255, 255, .4);
border-radius: 8px;
opacity: 0.4;
border: 1px solid #e1e2e6;
padding: 13px 16px;
margin-bottom: 12px;
text-align: center;
}
.check {
font-size: 15px;
color: #3d7ef0;
text-align: center;
}
}
.singleChecked {
border: 2px solid #73d8c0 !important;
font-size: 15px;
background: #FFFFFF !important;
color: #191B21;
}
.disSelect {
pointer-events: none;
}
.disSelectBtn {
pointer-events: none;
color: rgba(61, 126, 240, 0.3) !important;
}
}
.upDownBtn {
position: absolute;
right: 20px;
bottom: 30px;
display: flex;
flex-direction: column;
}
</style>
浙公网安备 33010602011771号