Files
property-resident-side/property-uniapp-project/pageSubPack/service-list/questionnaireDetail.vue
zhouyanli c862c6ae4b 修改bug
2026-08-26 14:10:23 +08:00

226 lines
4.5 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="contentStyle">
<scroll-view class="page" scroll-y="true">
<view class="survey-title">{{ detailItem.title || '' }}</view>
<view class="survey-desc">
为了给您提供更好的服务希望您能抽出几分钟时间将最近的感受和建议告诉我们
我们十分重视每位用户的宝贵意见期待您的参与
</view>
<view v-if="questionList.length === 0" class="empty-tip">
<text>暂无问卷内容</text>
</view>
<view v-for="(q, idx) in questionList" :key="q.cid" class="question-item">
<view class="question-title">
<text v-if="q.required" class="required">*</text>
<text>{{ idx + 1 }}.{{ q.title || '未命名问题' }}</text>
</view>
<!-- radio / checkbox: 展示选项及选中状态 -->
<view v-if="q.type === 'radio' || q.type === 'checkbox'" class="option-list">
<view
v-for="(opt, oIdx) in q.options"
:key="oIdx"
class="option-item"
:class="{ active: isOptionSelected(q, opt.label) }"
>
<text class="option-icon">{{ q.type === 'radio' ? '●' : '■' }}</text>
<text class="option-label">{{ opt.label }}</text>
</view>
</view>
<!-- input / textarea: 展示文本答案 -->
<view v-if="q.type === 'input' || q.type === 'textarea'" class="answer-text">
{{ getAnswerText(q.cid) || '未填写' }}
</view>
</view>
</scroll-view>
</view>
</template>
<script setup>
import { ref, computed } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { getQuestionnaireDetail } from '../api/apiSub.js'
const currentId = ref('')
const detailItem = ref({})
const questionList = computed(() => {
const content = detailItem.value?.content
if (!content) return []
try {
const list = JSON.parse(content)
return Array.isArray(list) ? list : []
} catch (e) {
return []
}
})
const answerMap = computed(() => {
const answerContent = detailItem.value?.myAnswer
if (!answerContent) return {}
try {
const list = JSON.parse(answerContent)
if (!Array.isArray(list)) return {}
const map = {}
for (const item of list) {
map[item.cid] = item.value
}
return map
} catch (e) {
return {}
}
})
const getDetailData = async () => {
try {
const params = { villageId: uni.getStorageSync('currentVillageId') }
const res = await getQuestionnaireDetail(currentId.value, params)
if (res.code === 200) {
const data = Array.isArray(res.data) ? res.data[0] : res.data
detailItem.value = data || {}
} else {
detailItem.value = {}
uni.showToast({ title: res.msg || '获取失败', icon: 'none' })
}
} catch (err) {
uni.showToast({ title: err.msg || '网络异常', icon: 'none' })
}
}
onLoad((option) => {
if (option.id) {
currentId.value = option.id
getDetailData()
}
})
function isOptionSelected(question, label) {
const val = answerMap.value[question.cid]
if (val === undefined || val === null) return false
if (Array.isArray(val)) {
return val.includes(label)
}
return val === label
}
function getAnswerText(cid) {
return answerMap.value[cid]
}
function goBack() {
uni.navigateBack()
}
</script>
<style lang="scss">
page {
background: #fff;
}
</style>
<style scoped>
.contentStyle {
display: flex;
flex-direction: column;
height: 100vh;
background: linear-gradient(to left bottom, #e2efff 0%, #f9f9f9 50%);
}
.page {
flex: 1;
overflow-y: auto;
padding: 20px 40rpx;
box-sizing: border-box;
margin-bottom: 48rpx;
}
.survey-title {
font-size: 32rpx;
font-weight: 600;
color: #333;
text-align: center;
margin: 0px 0 20rpx 0;
}
.survey-desc {
font-size: 24rpx;
color: #4A4A4A;
line-height: 1.6;
margin-bottom: 20rpx;
text-align: justify;
word-break: break-all;
word-wrap: break-word;
}
.empty-tip {
text-align: center;
padding: 100rpx 0;
font-size: 28rpx;
color: #999;
}
.question-item {
margin-bottom: 30rpx;
}
.question-title {
font-size: 32rpx;
color: #000;
margin-bottom: 10rpx;
font-weight: 600;
}
.required {
color: #ff0000;
font-size: 34rpx;
margin-right: 8rpx;
}
.answer-text {
font-size: 32rpx;
color: #333;
line-height: 1.5;
padding-left: 30rpx;
word-break: break-all;
word-wrap: break-word;
}
.option-list {
padding-left: 30rpx;
}
.option-item {
display: flex;
align-items: center;
gap: 16rpx;
padding: 16rpx 0;
font-size: 32rpx;
color: #333;
}
.option-item.active {
color: #409eff;
}
.option-icon {
font-size: 24rpx;
color: #ccc;
}
.option-item.active .option-icon {
color: #409eff;
}
.option-label {
font-size: 32rpx;
}
.status-bar {
width: 100vw;
height: 46px;
}
</style>