<template>
|
|
<view class="page__view">
|
|
<navbar :title="`问题 ${current + 1}/${total}`" leftClick @leftClick="$utils.navigateBack" color="#191919" bgColor="transparent" />
|
|
|
|
<template v-if="currentQuestion">
|
|
|
|
<view class="bar">
|
|
<view class="flex tools">
|
|
<view class="left">
|
|
<button class="flex btn" v-if="showPreBtn" @click="pre">
|
|
<image class="btn-icon" src="@/pages_order/static/report/icon-wrapper.png" mode="widthFix"></image>
|
|
<text>上一题</text>
|
|
</button>
|
|
</view>
|
|
<view class="right">
|
|
选择你的答案进入下一题
|
|
</view>
|
|
</view>
|
|
<view class="progress">
|
|
<view class="progress-bar" :style="{ width: `${progress}%` }"></view>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="main">
|
|
<view class="question">{{ currentQuestion.question }}</view>
|
|
<template v-if="currentQuestion.component === 'select'">
|
|
<view class="select">
|
|
<view
|
|
v-for="item in currentQuestion.options"
|
|
:key="item.id"
|
|
:class="['flex', 'select-option', item.id === value ? 'is-active' : '']"
|
|
@click="onSelect(item.id)"
|
|
>
|
|
{{ item.content }}
|
|
</view>
|
|
</view>
|
|
</template>
|
|
<template v-else-if="currentQuestion.component === 'select-multiple'">
|
|
<view class="select">
|
|
<view
|
|
v-for="item in currentQuestion.options"
|
|
:key="item.id"
|
|
:class="['flex', 'select-option', value.includes(item.id) ? 'is-active' : '']"
|
|
@click="onSelectMulitple(item.id)"
|
|
>
|
|
{{ item.content }}
|
|
</view>
|
|
</view>
|
|
</template>
|
|
<template v-else-if="currentQuestion.component === 'select-box'">
|
|
<view class="select-box">
|
|
<view
|
|
v-for="item in currentQuestion.options"
|
|
:key="item.id"
|
|
:class="['flex', 'flex-column', 'select-box-option', item.id === value ? 'is-active' : '']"
|
|
@click="onSelect(item.id)"
|
|
>
|
|
<image class="img" :src="item.id === value ? item.imageAfter : item.image" mode="aspectFit"></image>
|
|
<view class="text">{{ item.content }}</view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
<template v-else-if="currentQuestion.component === 'select-box-multiple'">
|
|
<view class="select-box">
|
|
<view
|
|
v-for="item in currentQuestion.options"
|
|
:key="item.id"
|
|
:class="['flex', 'flex-column', 'select-box-option', value.includes(item.id) ? 'is-active' : '']"
|
|
@click="onSelectMulitple(item.id)"
|
|
>
|
|
<image class="img" :src="value.includes(item.id) ? item.imageAfter : item.image" mode="aspectFit"></image>
|
|
<view class="text">{{ item.content }}</view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
<template v-else-if="currentQuestion.component === 'input'">
|
|
<view class="input">
|
|
<view class="flex input-box">
|
|
<view class="input-label" v-if="currentQuestion.options[0].prefix">{{ currentQuestion.options[0].prefix }}</view>
|
|
<input class="input-doc" v-model="value" :type="currentQuestion.options[0].inputType || 'text'" placeholder="请输入内容" placeholder-style="font-family: PingFang SC; font-weight: 400; line-height: 1.4; font-size: 32rpx; color: #AAAACA;" />
|
|
<view class="input-unit" v-if="currentQuestion.options[0].suffix">{{ currentQuestion.options[0].suffix }}</view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
<template v-else-if="currentQuestion.component === 'input-group'">
|
|
<view class="input">
|
|
<view class="flex input-box" v-for="(item, index) in currentQuestion.options" :key="item.id">
|
|
<view class="input-label" v-if="item.prefix">{{ item.prefix }}</view>
|
|
<input class="input-doc" v-model="value[index]" :type="currentQuestion.options[index].inputType || 'text'" placeholder="请输入内容" placeholder-style="font-family: PingFang SC; font-weight: 400; line-height: 1.4; font-size: 32rpx; color: #AAAACA;" />
|
|
<view class="input-unit" v-if="item.suffix">{{ item.suffix }}</view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
<view class="flex btns">
|
|
<button :class="['btn', 'btn-palin', noneFlag ? 'is-active' : '']" v-if="!currentQuestion.required" @click="onSelectNone">暂 无</button>
|
|
<button class="btn" v-if="showConfirmBtn" @click="onConfirm">确 认</button>
|
|
<button class="btn" v-if="showSubmitBtn" @click="onSubmit">提 交</button>
|
|
</view>
|
|
<view class="desc" v-if="currentQuestion.desc">
|
|
<uv-parse :content="currentQuestion.desc"></uv-parse>
|
|
</view>
|
|
</view>
|
|
|
|
</template>
|
|
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
import { mapState } from 'vuex'
|
|
|
|
export default {
|
|
data() {
|
|
return {
|
|
step: 0,
|
|
current: null,
|
|
tabs: [],
|
|
value: null,
|
|
noneFlag: false,
|
|
answers: [],
|
|
// tags: [],
|
|
questionsList: [],
|
|
total: 0,
|
|
}
|
|
},
|
|
computed: {
|
|
...mapState(['paperInfo', 'paperTags']),
|
|
preIdx() {
|
|
let index = this.tabs.findIndex(index => index === this.current)
|
|
return index - 1
|
|
},
|
|
showPreBtn() {
|
|
return this.preIdx >= 0
|
|
},
|
|
progress() {
|
|
return 100 * (this.current + 1) / this.total
|
|
},
|
|
showSubmitBtn() {
|
|
return this.current + 1 === this.total
|
|
},
|
|
currentQuestion() {
|
|
return this.questionsList[this.current]
|
|
},
|
|
showConfirmBtn() {
|
|
if (this.showSubmitBtn) {
|
|
return false
|
|
}
|
|
|
|
return ['select-box-multiple', 'select-multiple','input', 'input-group'].includes(this.currentQuestion?.component)
|
|
},
|
|
},
|
|
onLoad(arg) {
|
|
this.step = parseInt(arg.step)
|
|
// this.current = parseInt(arg.current || 0)
|
|
console.log('paperTags', this.paperTags)
|
|
this.fetchQuestionList()
|
|
this.switchQuestion(parseInt(arg.current || 0))
|
|
this.value = this.answers[this.current]
|
|
|
|
console.log('currentQuestion', this.currentQuestion)
|
|
},
|
|
methods: {
|
|
fetchQuestionList() {
|
|
|
|
const { category: categoryList } = this.paperInfo
|
|
const category = categoryList[this.step]
|
|
|
|
const { questionsList } = category
|
|
this.questionsList = questionsList.map(item => {
|
|
const { id, text, type, options, needTag, required, multiple: _multiple, content } = item
|
|
|
|
let component = 'select'
|
|
const multiple = _multiple == 'Y'
|
|
|
|
switch(type) { // 0-单选题 1-填空题 2-图片单选题
|
|
case '1':
|
|
component = options?.length > 1 ? 'input-group' : 'input'
|
|
break
|
|
case '2':
|
|
component = multiple ? 'select-box-multiple' : 'select-box'
|
|
break
|
|
default:
|
|
component = multiple ? 'select-multiple' : 'select'
|
|
break
|
|
}
|
|
|
|
return {
|
|
id,
|
|
question: text,
|
|
type,
|
|
component,
|
|
options,
|
|
needTag: needTag ? JSON.parse(needTag).map(config => config.tags).filter(tags => tags.length) : null,
|
|
required: required == 'Y',
|
|
multiple,
|
|
desc: content,
|
|
}
|
|
})
|
|
this.total = this.questionsList.length
|
|
|
|
this.answers = this.questionsList.map(item => {
|
|
let val = null
|
|
|
|
switch (item.component) {
|
|
case 'select-box-multiple':
|
|
case 'select-multiple':
|
|
val = []
|
|
break
|
|
case 'input-group':
|
|
val = new Array(item.options.length).fill(0).map(() => '')
|
|
break;
|
|
default:
|
|
val = null
|
|
break;
|
|
}
|
|
|
|
return val
|
|
})
|
|
// this.tags = this.paperTags[this.step]
|
|
// this.value = this.answers[this.current]
|
|
|
|
console.log('questionsList', this.questionsList)
|
|
console.log('answers', this.answers)
|
|
},
|
|
switchQuestion(current) {
|
|
let { needTag } = this.questionsList[current]
|
|
|
|
console.log('needTag length', needTag?.length)
|
|
if (!needTag?.length) {
|
|
this.current = current
|
|
this.tabs.push(this.current)
|
|
return
|
|
}
|
|
|
|
const selectTags = this.paperTags.flat(2)
|
|
console.log('selectTags', selectTags)
|
|
console.log('needTag', needTag)
|
|
|
|
let valid = needTag.some(tags => {
|
|
return tags.every(tag => {
|
|
const { value, exclude } = tag
|
|
|
|
let include = selectTags.includes(value)
|
|
|
|
return exclude ? !include : include
|
|
})
|
|
})
|
|
console.log('valid', valid)
|
|
|
|
if (valid) {
|
|
this.current = current
|
|
this.tabs.push(this.current)
|
|
return
|
|
}
|
|
|
|
if (current + 1 < this.questionsList.length) {
|
|
current += 1
|
|
this.switchQuestion(current)
|
|
return
|
|
}
|
|
|
|
this.$utils.redirectTo(`/pages_order/report/test/step?step=${this.step + 1}`)
|
|
},
|
|
pre() {
|
|
// this.current -= 1
|
|
this.current = this.preIdx
|
|
this.value = this.answers[this.current]
|
|
this.noneFlag = false
|
|
},
|
|
next() {
|
|
if (this.showSubmitBtn) {
|
|
return
|
|
}
|
|
// this.current += 1
|
|
this.switchQuestion(this.current + 1)
|
|
this.value = this.answers[this.current]
|
|
this.noneFlag = false
|
|
},
|
|
async fetchAnswer() {
|
|
try {
|
|
const { id: questionsId, type, required, multiple, options } = this.currentQuestion
|
|
|
|
console.log('paperInfo', this.paperInfo)
|
|
console.log('currentQuestion', this.currentQuestion)
|
|
console.log('required', required, 'noneFlag', this.noneFlag, 'value', this.value)
|
|
if (required && !this.noneFlag && (!this.value || !this.value?.length || this.value?.every?.(val => !val))) {
|
|
console.log('未答题')
|
|
uni.showToast({
|
|
title: '请答题',
|
|
icon:'none'
|
|
})
|
|
|
|
return false
|
|
}
|
|
|
|
let answer
|
|
|
|
// 0-单选题 1-填空题 2-图片单选题
|
|
if (type == 1) {
|
|
answer = options.reduce((obj, option, oIdx) => {
|
|
const { id: optionsId } = option
|
|
|
|
obj[optionsId] = Array.isArray(this.value) ? this.value[oIdx] : this.value
|
|
|
|
return obj
|
|
}, {})
|
|
answer = JSON.stringify(answer)
|
|
} else if (multiple && Array.isArray(this.value)) { // 多选题
|
|
answer = this.value.join(',')
|
|
}
|
|
|
|
let params = {
|
|
id: this.paperInfo.reportId,
|
|
questionsId,
|
|
answer
|
|
}
|
|
console.log('params', params)
|
|
await this.$fetch('answerPaper', params)
|
|
|
|
this.answers[this.current] = this.value
|
|
|
|
let paperTags = [...this.paperTags]
|
|
if (type == 1) {
|
|
paperTags[this.step][this.current] = []
|
|
} else {
|
|
let selectedIdArr = Array.isArray(this.value) ? this.value : [this.value]
|
|
console.log('selectedIdArr', selectedIdArr, 'options', options)
|
|
|
|
paperTags[this.step][this.current] = selectedIdArr.reduce((arr, id) => {
|
|
const { settingTag } = options.find(item => item.id === id) || {}
|
|
|
|
if (settingTag) {
|
|
const tags = settingTag?.split?.(',')
|
|
tags?.length && (arr = arr.concat(tags))
|
|
}
|
|
|
|
return arr
|
|
}, [])
|
|
|
|
}
|
|
console.log('paperTags', paperTags)
|
|
this.$store.commit('setPaperTags', paperTags)
|
|
|
|
return true
|
|
} catch (err) {
|
|
console.log('answerPaper', err)
|
|
return false
|
|
}
|
|
},
|
|
async onSelect(id) {
|
|
this.value = id
|
|
|
|
if (this.showSubmitBtn) {
|
|
return
|
|
}
|
|
|
|
let succ = await this.fetchAnswer()
|
|
|
|
if (!succ) {
|
|
return
|
|
}
|
|
|
|
this.$nextTick(() => {
|
|
setTimeout(() => {
|
|
this.next()
|
|
}, 500)
|
|
})
|
|
},
|
|
async onSelectMulitple(id) {
|
|
this.value = this.value.includes(id) ? this.value.filter(item => item !== id) : this.value.concat(id)
|
|
},
|
|
async onConfirm() {
|
|
let succ = await this.fetchAnswer()
|
|
|
|
if (!succ) {
|
|
return
|
|
}
|
|
|
|
this.next()
|
|
},
|
|
async onSelectNone() {
|
|
this.noneFlag = true
|
|
|
|
let val = null
|
|
|
|
switch (this.currentQuestion.component) {
|
|
case 'select-box-multiple':
|
|
case 'select-multiple':
|
|
val = []
|
|
break
|
|
case 'input-group':
|
|
val = new Array(this.currentQuestion.options.length).fill(0).map(() => '')
|
|
break;
|
|
default:
|
|
val = null
|
|
break;
|
|
}
|
|
|
|
this.value = val
|
|
|
|
let succ = await this.fetchAnswer()
|
|
|
|
if (!succ) {
|
|
return
|
|
}
|
|
|
|
this.next()
|
|
},
|
|
async onSubmit() {
|
|
let succ = await this.fetchAnswer()
|
|
|
|
if (!succ) {
|
|
return
|
|
}
|
|
|
|
const { category } = this.paperInfo
|
|
|
|
if (this.step == category.length - 1) {
|
|
|
|
await this.$fetch('submitPaper', { id: this.paperInfo.reportId })
|
|
|
|
uni.reLaunch({
|
|
url: '/pages/index/report'
|
|
})
|
|
return
|
|
}
|
|
|
|
this.$utils.redirectTo(`/pages_order/report/test/step?step=${this.step + 1}`)
|
|
|
|
},
|
|
},
|
|
}
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
.page__view {
|
|
width: 100vw;
|
|
min-height: 100vh;
|
|
background-color: $uni-bg-color;
|
|
position: relative;
|
|
}
|
|
|
|
.bar {
|
|
margin-top: 24rpx;
|
|
width: 100%;
|
|
padding: 0 32rpx;
|
|
box-sizing: border-box;
|
|
|
|
.left {
|
|
text-align: left;
|
|
|
|
.btn {
|
|
display: inline-flex;
|
|
font-family: PingFang SC;
|
|
font-weight: 400;
|
|
font-size: 30rpx;
|
|
line-height: 1.4;
|
|
color: #7451DE;
|
|
|
|
&-icon {
|
|
width: 32rpx;
|
|
height: auto;
|
|
margin-right: 8rpx;
|
|
}
|
|
}
|
|
}
|
|
|
|
.right {
|
|
flex: 1;
|
|
text-align: right;
|
|
font-family: PingFang SC;
|
|
font-weight: 400;
|
|
font-size: 26rpx;
|
|
line-height: 1.4;
|
|
color: #989898;
|
|
}
|
|
}
|
|
|
|
.progress {
|
|
margin-top: 24rpx;
|
|
width: 100%;
|
|
height: 24rpx;
|
|
background: #E5E5E5;
|
|
border-radius: 12rpx;
|
|
|
|
&-bar {
|
|
height: 100%;
|
|
background-image: linear-gradient(to right, #4B348F, #845CFA);
|
|
border-radius: 12rpx;
|
|
}
|
|
}
|
|
|
|
.main {
|
|
width: 100%;
|
|
padding: 70rpx 104rpx 0 104rpx;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
.question {
|
|
text-align: center;
|
|
font-family: PingFang SC;
|
|
font-weight: 400;
|
|
font-size: 40rpx;
|
|
line-height: 1.4;
|
|
color: #000000;
|
|
margin-bottom: 64rpx;
|
|
}
|
|
|
|
.select {
|
|
&-option {
|
|
padding: 30rpx 0;
|
|
font-family: PingFang SC;
|
|
font-weight: 400;
|
|
line-height: 1.4;
|
|
font-size: 32rpx;
|
|
color: #252545;
|
|
background-image: linear-gradient(to right, #FFFFFF, #F4F4F6, #F2F2F4);
|
|
border-radius: 52rpx;
|
|
box-shadow: -2rpx -2rpx 10rpx 0 #FFFFFFC4,
|
|
4rpx 4rpx 20rpx 0 #AAAACC1F,
|
|
2rpx 2rpx 4rpx 0 #AAAACC40,
|
|
-1rpx -1rpx 2rpx 0 #FFFFFF;
|
|
|
|
& + & {
|
|
margin-top: 40rpx;
|
|
}
|
|
|
|
&.is-active {
|
|
color: #FFFFFF;
|
|
background: #7451DE;
|
|
}
|
|
}
|
|
}
|
|
|
|
.select-box {
|
|
display: grid;
|
|
grid-template-columns: repeat(3, 1fr);
|
|
gap: 32rpx;
|
|
|
|
&-option {
|
|
padding: 24rpx 0;
|
|
border-radius: 24rpx;
|
|
background-image: linear-gradient(to right, #FFFFFF, #F2F2F4);
|
|
box-shadow: -2rpx -2rpx 10rpx 0 #FFFFFFC4,
|
|
4rpx 4rpx 20rpx 0 #AAAACC1F,
|
|
2rpx 2rpx 4rpx 0 #AAAACC40,
|
|
-1rpx -1rpx 2rpx 0 #FFFFFF;
|
|
|
|
.img {
|
|
width: 100%;
|
|
height: 64rpx;
|
|
}
|
|
|
|
.text {
|
|
margin-top: 8rpx;
|
|
font-family: PingFang SC;
|
|
font-weight: 400;
|
|
font-size: 28rpx;
|
|
line-height: 1.4;
|
|
color: #969696;
|
|
}
|
|
|
|
&.is-active {
|
|
background: #7451DE;
|
|
|
|
.text {
|
|
color: #FFFFFFC4;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.input {
|
|
&-box {
|
|
width: 100%;
|
|
height: 104rpx;
|
|
padding: 0 40rpx;
|
|
box-sizing: border-box;
|
|
border-radius: 52rpx;
|
|
background-image: linear-gradient(to right, #FFFFFF, #F4F4F6, #F2F2F4);
|
|
box-shadow: -2rpx -2rpx 10rpx 0 #FFFFFFC4,
|
|
4rpx 4rpx 20rpx 0 #AAAACC1F,
|
|
2rpx 2rpx 4rpx 0 #AAAACC40,
|
|
-1rpx -1rpx 2rpx 0 #FFFFFF;
|
|
|
|
& + & {
|
|
margin-top: 40rpx;
|
|
}
|
|
}
|
|
|
|
&-doc {
|
|
text-align: center;
|
|
flex: 1;
|
|
}
|
|
|
|
&-label {
|
|
padding: 21rpx 40rpx 21rpx 0;
|
|
font-family: PingFang SC;
|
|
font-weight: 600;
|
|
font-size: 30rpx;
|
|
line-height: 1.4;
|
|
color: #252545;
|
|
border-right: 2rpx solid #E0DFF0;
|
|
}
|
|
|
|
&-unit {
|
|
padding: 21rpx 0 21rpx 40rpx;
|
|
font-family: PingFang SC;
|
|
font-weight: 600;
|
|
font-size: 30rpx;
|
|
line-height: 1.4;
|
|
color: #252545;
|
|
border-left: 2rpx solid #E0DFF0;
|
|
}
|
|
}
|
|
|
|
.btns {
|
|
margin-top: 64rpx;
|
|
column-gap: 36rpx;
|
|
.btn {
|
|
flex: 1;
|
|
padding: 24rpx 0;
|
|
font-family: PingFang SC;
|
|
font-weight: 600;
|
|
font-size: 30rpx;
|
|
line-height: 1.4;
|
|
color: #FFFFFF;
|
|
background-image: linear-gradient(to right, #4B348F, #845CFA);
|
|
border-radius: 45rpx;
|
|
|
|
&-palin {
|
|
padding: 22rpx 0;
|
|
font-weight: 400;
|
|
color: #252545;
|
|
background: transparent;
|
|
border: 2rpx solid #252545;
|
|
|
|
&.is-active {
|
|
color: $uni-color;
|
|
border-color: $uni-color;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.desc {
|
|
margin-top: 220rpx;
|
|
font-family: PingFang SC;
|
|
font-weight: 400;
|
|
line-height: 1.4;
|
|
font-size: 26rpx;
|
|
color: #989898;
|
|
}
|
|
|
|
</style>
|