Переглянути джерело

feat: show perill questionnaire one question at a time

Developer 2 місяців тому
батько
коміт
9a15ac3c42
1 змінених файлів з 57 додано та 53 видалено
  1. 57 53
      pages/questionnaireFill2.vue

+ 57 - 53
pages/questionnaireFill2.vue

@@ -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>