358 lines
10 KiB
Vue
358 lines
10 KiB
Vue
<template>
|
|
<section class="formDetail">
|
|
<ai-result v-if="result.tips" v-bind="result">
|
|
<template v-if="isExam" #extra>
|
|
<div flex class="scorePane">
|
|
<div>成绩</div>
|
|
<div class="fill"><em v-html="score"/> 分</div>
|
|
</div>
|
|
</template>
|
|
</ai-result>
|
|
<template v-else-if="form.id">
|
|
<image v-if="form.headPicture" class="headPicture" :src="form.headPicture"/>
|
|
<b class="title">{{ form.title || "标题" }}</b>
|
|
<div class="tableExplain">{{ form.tableExplain }}</div>
|
|
<u-form class="content" label-position="top">
|
|
<u-form-item class="item" v-for="(op,i) in fields" :key="i" :label="(i+1)+'.'+op.fieldName"
|
|
:required="op.fieldInfo.required==1">
|
|
<template v-if="op.fieldType=='input'">
|
|
<input v-model="op.fieldValue" :placeholder="op.fieldInfo.placeholder" :disabled="isResult"/>
|
|
</template>
|
|
<template v-else-if="op.fieldType=='textarea'">
|
|
<textarea v-model="op.fieldValue" :disabled="isResult" :placeholder="op.fieldInfo.placeholder"/>
|
|
</template>
|
|
<template v-else-if="op.fieldType=='upload'">
|
|
<ai-uploader @list="v=>op.fieldValue=v.map(e=>e.url)" :def="op.fieldValue" :disabled="isResult"
|
|
preview action="/admin/file/add2"/>
|
|
</template>
|
|
<u-row v-else-if="op.fieldType=='radio'">
|
|
<radio-group @change="({detail})=>op.fieldValue=detail.value">
|
|
<div class="option" flex v-for="option in op.fieldInfo.options" :key="option.label">
|
|
<radio :value="option.label" :disabled="isResult" :checked="op.fieldValue==option.label"/>
|
|
<ai-image v-if="option.img" :src="option.img" preview/>
|
|
<div class="label fill">{{ option.label }}</div>
|
|
</div>
|
|
</radio-group>
|
|
</u-row>
|
|
<u-row v-else-if="op.fieldType=='checkbox'">
|
|
<checkbox-group @change="({detail})=>op.fieldValue=detail.value">
|
|
<div class="option" flex v-for="option in op.fieldInfo.options" :key="option.label">
|
|
<checkbox :value="option.label" :disabled="isResult"
|
|
:checked="option.checked"/>
|
|
<ai-image v-if="option.img" :src="option.img" preview/>
|
|
<div class="label fill">{{ option.label }}</div>
|
|
</div>
|
|
</checkbox-group>
|
|
</u-row>
|
|
<template v-else-if="op.fieldType=='select'">
|
|
<ai-select @data="v=>op.fieldValue=v.map(e=>e.value)" :list="op.fieldInfo.options" :disabled="isResult">
|
|
<div class="option" flex>
|
|
<div class="label fill" v-if="op.fieldValue">{{ op.fieldValue.toString() }}</div>
|
|
<i class="fill" v-else>请选择</i>
|
|
<u-icon name="arrow-right" color="#ddd"/>
|
|
</div>
|
|
</ai-select>
|
|
</template>
|
|
</u-form-item>
|
|
</u-form>
|
|
<div class="bottom" v-if="!(isPreview||isResult)">
|
|
<div class="bottomBtn" @tap="handleSubmit">提交</div>
|
|
</div>
|
|
</template>
|
|
<ai-loading v-else tips="调查问卷加载中..."/>
|
|
</section>
|
|
</template>
|
|
|
|
<script>
|
|
|
|
import {mapState} from "vuex";
|
|
import AiTextarea from "../../components/AiTextarea";
|
|
import AiUploader from "../../components/AiUploader";
|
|
import AiSelect from "../../components/AiSelect";
|
|
import AiLoading from "../../components/AiLoading";
|
|
import AiResult from "../../components/AiResult";
|
|
import AiImage from "../../components/AiImage";
|
|
import AiBack from "../../components/AiBack";
|
|
|
|
export default {
|
|
name: "formDetail",
|
|
inject: {root: {}},
|
|
components: {
|
|
AiBack,
|
|
AiImage,
|
|
AiResult,
|
|
AiLoading,
|
|
AiSelect,
|
|
AiUploader,
|
|
AiTextarea,
|
|
},
|
|
computed: {
|
|
...mapState(['openUser', 'token']),
|
|
isExam() {
|
|
return this.form?.type == 1
|
|
},
|
|
isResult() {
|
|
return !!this.$route.query?.result
|
|
},
|
|
isPreview() {
|
|
return !!this.$route.query?.preview
|
|
}
|
|
},
|
|
data() {
|
|
return {
|
|
form: {},
|
|
fields: [],
|
|
checkUser: false,
|
|
result: {},
|
|
score: 0
|
|
}
|
|
},
|
|
watch: {
|
|
form: {
|
|
deep: true,
|
|
handler(v) {
|
|
this.fields = v?.fields?.map(e => {
|
|
let fieldInfo = JSON.parse(e.fieldInfo)
|
|
fieldInfo?.options?.map(op => {
|
|
op.img = op?.img?.[0]?.url
|
|
op.checked = !!e.fieldValue?.split(",")?.includes(op.label)
|
|
})
|
|
if (e.fieldType == 'select') {
|
|
fieldInfo.options = fieldInfo.options.map(e => ({...e, value: e.label, label: e.label}))
|
|
}
|
|
return {...e, fieldInfo}
|
|
}) || []
|
|
}
|
|
}
|
|
},
|
|
methods: {
|
|
getForm() {
|
|
let {id} = this.$route.query
|
|
this.$http.post("/app/appquestionnairetemplate/queryDetailById", null, {
|
|
withoutToken: true,
|
|
params: {id}
|
|
}).then(res => {
|
|
if (res?.data) {
|
|
this.form = res.data
|
|
}
|
|
})
|
|
},
|
|
getResult() {
|
|
let {id} = this.$route.query
|
|
this.$http.post("/app/appquestionnairetemplate/commitCheck", null, {
|
|
params: {id}
|
|
}).then(res => {
|
|
if (res?.data) {
|
|
this.form = res.data
|
|
}
|
|
})
|
|
},
|
|
validateForm() {
|
|
return !this.fields.some(e => {
|
|
if (!!e?.fieldInfo?.required && !e.fieldValue?.toString()) {
|
|
this.$u.toast(e.fieldName + "不能为空!")
|
|
return true
|
|
}
|
|
})
|
|
},
|
|
handleSubmit() {
|
|
if (this.validateForm()) {
|
|
this.handleScore()
|
|
let {avatar: avatarUrl, openId, name: nickName, type: userType, unionId, corpName} = this.openUser
|
|
this.$http.post("/app/appquestionnairetemplate/commit", {
|
|
fields: this.fields.map(e => ({
|
|
...e,
|
|
fieldInfo: JSON.stringify(e.fieldInfo),
|
|
fieldValue: e.fieldValue?.toString()
|
|
})),
|
|
avatarUrl, openId, nickName, userType, unionId, corpName,
|
|
totalScore: this.score,
|
|
questionnaireTemplateId: this.$route.query.id
|
|
}).then(res => {
|
|
if (res?.code == 0) {
|
|
this.result = {
|
|
tips: "提交成功!感谢参与",
|
|
}
|
|
}
|
|
}).catch(err => {
|
|
this.$u.toast(err || "提交失败")
|
|
})
|
|
}
|
|
},
|
|
handleScore() {
|
|
this.score = 0
|
|
this.isExam && this.fields.map(field => {
|
|
let item = field?.fieldInfo || {}
|
|
let current = 0
|
|
const calcScore = point => (current += (Number(point) || 0))
|
|
if (item?.pointType == 0) {//此题有唯一答案和分值
|
|
field.fieldValue?.toString() == item.answer?.toString() && calcScore(item?.points)
|
|
} else if (item?.pointType == 1) {//每个选项都有对应分值
|
|
item?.options?.map(op => {
|
|
if (typeof field.fieldValue == "object") {
|
|
if (field.fieldValue?.includes(op.label)) {
|
|
calcScore(op.point)
|
|
}
|
|
} else {
|
|
op.label == field.fieldValue && calcScore(op.point)
|
|
}
|
|
})
|
|
} else if (item?.pointType == 2) {//答对几项得几分,答错不得分
|
|
item?.options?.some(op => {
|
|
if (typeof field.fieldValue == "object") {
|
|
if (field.fieldValue?.includes(op.label)) {
|
|
if (item.answer?.includes(op.label)) calcScore(op.point)
|
|
else return current = 0
|
|
}
|
|
} else {
|
|
op.label == field.fieldValue && calcScore(op.point)
|
|
}
|
|
})
|
|
}
|
|
this.score += current
|
|
//打印每题打分
|
|
if (!!field.fieldValue) {
|
|
const typeResult = (reply, answer) => {
|
|
console.log("题目:%s,回答:%s,得分:%s,总分:%s \n 答案:%s", field.fieldName,
|
|
reply, current, this.score, answer)
|
|
}
|
|
typeResult(field.fieldValue?.toString(), item.answer?.toString())
|
|
}
|
|
})
|
|
},
|
|
},
|
|
created() {
|
|
this.isResult ? this.getResult() : this.getForm()
|
|
},
|
|
mounted() {
|
|
document.title = this.form.title || "调查问卷"
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.formDetail {
|
|
display: flex;
|
|
flex-direction: column;
|
|
background: #fff;
|
|
|
|
.headPicture {
|
|
width: 100%;
|
|
height: 320px;
|
|
|
|
.img {
|
|
width: 100%;
|
|
}
|
|
}
|
|
|
|
.title {
|
|
width: 100%;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
flex-wrap: wrap;
|
|
padding: 32px;
|
|
box-sizing: border-box;
|
|
font-size: 34px;
|
|
font-weight: bold;
|
|
color: #333;
|
|
line-height: 48px;
|
|
}
|
|
|
|
.bottom {
|
|
position: fixed;
|
|
bottom: 0;
|
|
width: 100%;
|
|
padding: 32px;
|
|
box-sizing: border-box;
|
|
background: #fff;
|
|
z-index: 99;
|
|
|
|
.bottomBtn {
|
|
width: 100%;
|
|
line-height: 96px;
|
|
background: #287DE1;
|
|
color: #fff;
|
|
text-align: center;
|
|
height: 96px;
|
|
font-size: 32px;
|
|
font-weight: bold;
|
|
border-radius: 8px;
|
|
}
|
|
}
|
|
|
|
.tableExplain {
|
|
font-size: 28px;
|
|
font-weight: 400;
|
|
color: #666;
|
|
padding: 32px 24px;
|
|
}
|
|
|
|
::v-deep .u-form-item {
|
|
.u-form-item--left {
|
|
font-size: 30px;
|
|
font-weight: bold;
|
|
color: #333;
|
|
}
|
|
|
|
.u-form-item--right__content__slot > * {
|
|
width: 100%;
|
|
}
|
|
|
|
.display {
|
|
justify-content: space-between;
|
|
min-height: 58px;
|
|
}
|
|
|
|
.uni-radio-input, .uni-checkbox-input {
|
|
height: 32px;
|
|
width: 32px;
|
|
}
|
|
|
|
.label {
|
|
flex-shrink: 0;
|
|
|
|
* + & {
|
|
margin-left: 16px;
|
|
}
|
|
}
|
|
|
|
.option {
|
|
width: 100%;
|
|
margin-right: 16px;
|
|
margin-bottom: 16px;
|
|
}
|
|
}
|
|
|
|
.content {
|
|
padding: 64px 32px 200px;
|
|
background: #fff;
|
|
}
|
|
|
|
::v-deep .scorePane {
|
|
width: calc(100% - 40px);
|
|
padding: 0 32px;
|
|
height: 124px;
|
|
background: #E9F2FF;
|
|
border-radius: 16px;
|
|
font-size: 30px;
|
|
font-weight: 500;
|
|
color: #333333;
|
|
margin-top: 48px;
|
|
box-sizing: border-box;
|
|
|
|
.fill {
|
|
text-align: center;
|
|
}
|
|
|
|
em {
|
|
font-size: 48px;
|
|
font-weight: bold;
|
|
color: #2C72FE;
|
|
font-style: normal;
|
|
margin-right: 8px;
|
|
}
|
|
}
|
|
}
|
|
</style>
|