|
|
@@ -4,9 +4,9 @@
|
|
|
<div class="top adffcacjc">
|
|
|
<p>{{ title }}</p>
|
|
|
<p class="tip">
|
|
|
- 共
|
|
|
- <span>{{ list.length }}</span>
|
|
|
- 题,已作答
|
|
|
+ 第
|
|
|
+ <span>{{ currentIndex + 1 }}</span>
|
|
|
+ /{{ list.length }} 题,已作答
|
|
|
<span style="font-weight: bold">{{ answerNum }}</span>
|
|
|
题,请耐心选择!
|
|
|
</p>
|
|
|
@@ -19,15 +19,16 @@
|
|
|
</div>
|
|
|
</div>
|
|
|
<template v-else>
|
|
|
- <view>
|
|
|
- <div class="l_item" v-for="(item, index) in list" :key="item.id" :id="'question-' + index">
|
|
|
- <QuestionItem :item="item" :index="index" @change="handleAnswerChange"></QuestionItem>
|
|
|
- </div>
|
|
|
- </view>
|
|
|
+ <div v-if="currentQuestion" class="l_item" :id="'question-' + currentIndex">
|
|
|
+ <QuestionItem :item="currentQuestion" :index="currentIndex" @change="handleAnswerChange"></QuestionItem>
|
|
|
+ </div>
|
|
|
</template>
|
|
|
</scroll-view>
|
|
|
- <div class="bottom">
|
|
|
- <view class="zt_btn" @tap="submitWj">{{ isSubmitting ? '提交中...' : '提交问卷' }}</view>
|
|
|
+ <div class="bottom adfacjb">
|
|
|
+ <view class="zt_btn secondary" :class="{disabled: currentIndex === 0 || isSubmitting}" @tap="previousQuestion">上一题</view>
|
|
|
+ <view class="zt_btn" :class="{disabled: isSubmitting}" @tap="nextQuestion">
|
|
|
+ {{ currentIndex === list.length - 1 ? (isSubmitting ? '提交中...' : '提交问卷') : '下一题' }}
|
|
|
+ </view>
|
|
|
</div>
|
|
|
</view>
|
|
|
</template>
|
|
|
@@ -41,6 +42,7 @@ export default {
|
|
|
title: '',
|
|
|
teamQuestionnaireId: '',
|
|
|
list: [],
|
|
|
+ currentIndex: 0,
|
|
|
questionnaire: null,
|
|
|
isLoading: true,
|
|
|
isSubmitting: false,
|
|
|
@@ -57,6 +59,9 @@ export default {
|
|
|
computed: {
|
|
|
answerNum() {
|
|
|
return this.list.filter(l => l?.answer.filter(a => a?.value).length == this.userAnswerTemp.length).length || 0;
|
|
|
+ },
|
|
|
+ currentQuestion() {
|
|
|
+ return this.list[this.currentIndex] || null;
|
|
|
}
|
|
|
},
|
|
|
methods: {
|
|
|
@@ -116,12 +121,15 @@ export default {
|
|
|
warn: false
|
|
|
}
|
|
|
});
|
|
|
- this.list.forEach(l=>{
|
|
|
+ this.list.forEach(l=>{
|
|
|
let _a = answerMap.get(l.id);
|
|
|
l.userAnswer.forEach(u=>{
|
|
|
u.answer = _a?(_a.find(a=>a.assessmentMethod==u.assessmentMethod)?.value||''):''
|
|
|
- })
|
|
|
- })
|
|
|
+ })
|
|
|
+ })
|
|
|
+ const firstUnansweredIndex = this.list.findIndex(l =>
|
|
|
+ l.answer.filter(a => a && a.value).length !== this.userAnswerTemp.length)
|
|
|
+ this.currentIndex = firstUnansweredIndex === -1 ? 0 : firstUnansweredIndex
|
|
|
})
|
|
|
.catch(() => {
|
|
|
this.isLoading = false;
|
|
|
@@ -131,35 +139,26 @@ export default {
|
|
|
this.isLoading = false;
|
|
|
});
|
|
|
},
|
|
|
- scrollToQuestion(index) {
|
|
|
- const query = uni.createSelectorQuery().in(this);
|
|
|
- const targetId = `#question-${index}`;
|
|
|
- query.select(targetId).boundingClientRect();
|
|
|
- query.select('.list').scrollOffset(); // 获取 scroll-view 的滚动信息
|
|
|
- query.select('.list').boundingClientRect(); // 获取 scroll-view 自身的位置信息
|
|
|
- query.exec((res) => {
|
|
|
- // 增加安全校验
|
|
|
- if (!res || !res[0] || !res[1] || !res[2]) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // res[0]: 目标元素 (#question-N) 的位置信息
|
|
|
- const itemRect = res[0];
|
|
|
- // res[1]: 滚动容器 (.list) 的滚动信息
|
|
|
- const scrollViewScroll = res[1];
|
|
|
- // res[2]: 滚动容器 (.list) 自身的位置信息
|
|
|
- const scrollViewRect = res[2];
|
|
|
-
|
|
|
- // 计算目标滚动位置 = 当前滚动距离 + (目标元素顶部 - 滚动容器顶部) - 预留间距
|
|
|
- const targetPosition = scrollViewScroll.scrollTop + itemRect.top - scrollViewRect.top - 10; // 减10px作为顶部留白
|
|
|
-
|
|
|
- // 通过先设置为旧值,再在 nextTick 中设置为新值的方式,确保滚动能够触发
|
|
|
- this.scrollTop = this.oldScrollTop;
|
|
|
- this.$nextTick(() => {
|
|
|
- this.scrollTop = targetPosition;
|
|
|
- this.oldScrollTop = targetPosition;
|
|
|
- });
|
|
|
- });
|
|
|
+ previousQuestion() {
|
|
|
+ if (this.currentIndex === 0 || this.isSubmitting) return
|
|
|
+ this.currentIndex--
|
|
|
+ this.scrollTop = 0
|
|
|
+ },
|
|
|
+ nextQuestion() {
|
|
|
+ if (this.isSubmitting || !this.currentQuestion) return
|
|
|
+ const current = this.currentQuestion
|
|
|
+ const isAnswered = current.answer.filter(a => a && a.value).length === this.userAnswerTemp.length
|
|
|
+ this.$set(current, 'warn', !isAnswered)
|
|
|
+ if (!isAnswered) {
|
|
|
+ this.$showToast(`第 ${this.currentIndex + 1} 项未选择完整答案,请选择。`)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (this.currentIndex < this.list.length - 1) {
|
|
|
+ this.currentIndex++
|
|
|
+ this.scrollTop = 0
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.submitWj()
|
|
|
},
|
|
|
submitWj() {
|
|
|
if (this.isSubmitting) return;
|
|
|
@@ -174,17 +173,9 @@ export default {
|
|
|
});
|
|
|
|
|
|
if (firstUnansweredIndex > -1) {
|
|
|
- uni.showModal({
|
|
|
- title: '提示',
|
|
|
- content: `第 ${firstUnansweredIndex + 1} 项未选择答案,请选择。`,
|
|
|
- showCancel: false,
|
|
|
- success: (res) => {
|
|
|
- if (res.confirm) {
|
|
|
- // 调用新的滚动方法
|
|
|
- this.scrollToQuestion(firstUnansweredIndex);
|
|
|
- }
|
|
|
- }
|
|
|
- });
|
|
|
+ this.currentIndex = firstUnansweredIndex
|
|
|
+ this.scrollTop = 0
|
|
|
+ this.$showToast(`第 ${firstUnansweredIndex + 1} 项未选择完整答案,请选择。`)
|
|
|
return; // 终止提交
|
|
|
}
|
|
|
|
|
|
@@ -301,6 +292,19 @@ export default {
|
|
|
position: fixed;
|
|
|
left: 40rpx;
|
|
|
bottom: 40rpx;
|
|
|
+ gap: 20rpx;
|
|
|
+ .zt_btn {
|
|
|
+ flex: 1;
|
|
|
+ margin: 0;
|
|
|
+ &.secondary {
|
|
|
+ background: #FFFFFF;
|
|
|
+ border: 2rpx solid #33A7A7;
|
|
|
+ color: #33A7A7;
|
|
|
+ }
|
|
|
+ &.disabled {
|
|
|
+ opacity: .5;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
</style>
|