Prechádzať zdrojové kódy

fix: align perill questionnaire flow and title

Developer 2 týždňov pred
rodič
commit
b24a9b42bf

+ 3 - 3
pagesPublish/backgroundSurveyIntro.vue

@@ -15,7 +15,7 @@
 <script>
 	import CusHeader from '@/components/CusHeader/index.vue'
 	import backgroundSurveyRules from '@/utils/backgroundSurvey.js'
-	const { questionnaireFillUrl } = backgroundSurveyRules
+	const { questionnaireFillUrl, decodeQueryValue } = backgroundSurveyRules
 
 	export default {
 		components:{ CusHeader },
@@ -33,7 +33,7 @@
 			stageTitle(){
 				return this.stage === 'background'
 					? '团队背景调研'
-					: 'PERILL团队发展动态评估'
+					: 'PERILL倍力团队六维评估'
 			},
 			description(){
 				return this.stage === 'background'
@@ -53,7 +53,7 @@
 			this.teamId = options.teamId || ''
 			this.type = options.type || ''
 			this.turnType = options.turnType || ''
-			this.title = options.title || ''
+			this.title = decodeQueryValue(options.title || '')
 		},
 		methods:{
 			start(){

+ 109 - 42
pagesPublish/questionnaireFill.vue

@@ -8,7 +8,7 @@
 				<view class="top-progress-box">
 					<view class="top-progress-box-current" :style="{'width':(answerCount/list.length*100)+'%'}"></view>
 				</view>
-				<view class="top-progress-num"><span>{{answerCount}}</span>/{{list.length}}</view>
+			<view class="top-progress-num"><span>{{currentIndex + 1}}</span>/{{list.length}}</view>
 			</view>
 		</view>
 		<!-- <view class="memo adfac" v-if="turnType==='questionnaire'" @click="noticeShow=true">
@@ -23,11 +23,11 @@
 				</view>
 			</view>
 			<template v-else>
-				<view>
-					<view class="l_item" v-for="(item, index) in list" :key="item.id" :id="'question-' + index">
-						<question-item :item="item" :index="index" @change="handleAnswerChange"></question-item>
-					</view>
-				</view>
+				<view v-if="currentQuestion">
+					<view class="l_item" :id="'question-' + currentIndex">
+						<question-item :item="currentQuestion" :index="currentIndex" @change="handleAnswerChange"></question-item>
+					</view>
+				</view>
 			</template>
 		</scroll-view>
 		<!-- <view class="list">
@@ -35,16 +35,18 @@
 				<question-item :item="item" :index="index" @change="handleAnswerChange"></<question-item>
 			</view>
 		</view> -->
-		<view class="bottom adfacjb" v-if="type==1">
-			<view class="bottom-right" style="width: 100%;" @click="confirmSubmit">提交问卷</view>
-		</view>
-		<view class="bottom adfacjb" v-else-if="turnType==='questionnaire'">
-			<view class="bottom-left adffcac" @click="showTeamUser">
-				<image :src="imgBase+'questionnaire_users.png'"></image>
-				<text>团队人员</text>
-			</view>
-			<view class="bottom-right" :class="{'questionnaire':turnType==='questionnaire'}" @click="confirmSubmit">提交问卷</view>
-		</view>
+		<view class="bottom adfacjb">
+			<view class="bottom-left adffcac" v-if="turnType==='questionnaire'" @click="showTeamUser">
+				<image :src="imgBase+'questionnaire_users.png'"></image>
+				<text>团队人员</text>
+			</view>
+			<view class="question-nav adfacjb">
+				<view class="question-nav-btn secondary" :class="{disabled: currentIndex === 0 || isSubmitting}" @click="previousQuestion">上一题</view>
+				<view class="question-nav-btn primary" :class="{disabled: isSubmitting}" @click="nextQuestion">
+					{{currentIndex === list.length - 1 ? (isSubmitting ? '提交中...' : '提交问卷') : '下一题'}}
+				</view>
+			</view>
+		</view>
 		<cus-notice :show="noticeShow" @close="noticeShow=false" @handleKnow="noticeShow=false"></cus-notice>
 		<cus-team-info :show="teamShow" :teamInfo="teamInfo" @close="teamShow=false"></cus-team-info>
 		<cus-team-user :show="userShow" :canEdit="false" :list="teamUserList" @close="userShow=false"></cus-team-user>
@@ -61,7 +63,7 @@
 		components:{ CusNotice, QuestionItem, CusTeamInfo, CusTeamUser },
 		data(){
 			return {
-				title:'',
+				title:'',
 				type:'',
 				turnType:'',
 				questionnaireId:'',
@@ -71,6 +73,7 @@
 				teamUserList:[],
 				teamQuestionnaireId: '',
 				list: [],
+				currentIndex: 0,
 				questionnaire: null,
 				isLoading: true,
 				isSubmitting: false,
@@ -85,15 +88,33 @@
 				categoryData:[]
 			}
 		},
-		onLoad(options) {
-			this.title = options.title||'';
+			onLoad(options) {
+			this.title = this.decodeTitle(options.title).replace(/PERILL团队发展动态评估/g, 'PERILL倍力团队六维评估');
 			this.type = options.type;
 			this.turnType = options.turnType;
 			this.teamQuestionnaireId = options.teamQuestionnaireId;
 			this.teamId = options.teamId;
-			this.getList();
-		},
+			this.getList();
+		},
+		computed: {
+			currentQuestion() {
+				return this.list[this.currentIndex] || null;
+			}
+		},
 		methods:{
+			decodeTitle(title) {
+			let decoded = String(title || '')
+			for (let i = 0; i < 5; i += 1) {
+				try {
+					const next = decodeURIComponent(decoded)
+					if (next === decoded) break
+					decoded = next
+				} catch (error) {
+					break
+				}
+			}
+			return decoded || 'PERILL倍力团队六维评估'
+		},
 			handleAnswerChange(e) {
 				const item = this.list[e.index];
 				if (item) {
@@ -184,8 +205,10 @@
 							})
 						})
 						
-						this.answerCount = this.list.filter(l => l?.answer.filter(a => a?.value).length == this.userAnswerTemp.length).length;
-						this.isLoading = false;
+						this.answerCount = this.list.filter(l => l?.answer.filter(a => a?.value).length == this.userAnswerTemp.length).length;
+						const firstUnansweredIndex = this.list.findIndex(l => l.answer.filter(a => a?.value).length !== this.userAnswerTemp.length)
+						this.currentIndex = firstUnansweredIndex === -1 ? 0 : firstUnansweredIndex;
+						this.isLoading = false;
 					})
 					.catch(() => {
 						this.isLoading = false;
@@ -247,7 +270,34 @@
 					this.userShow = true
 				})
 			},
-			confirmSubmit() {
+			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 answerError = current.answer.filter(a => a?.value).length !== this.userAnswerTemp.length;
+				this.$set(current, 'warn', answerError);
+				if (answerError) {
+					this.$showToast(`第 ${this.currentIndex + 1} 项未选择完整答案,请选择。`);
+					return;
+				}
+				const expectationError = validateFutureExpectation(current.userAnswer);
+				this.$set(current, 'warn', !!expectationError);
+				if (expectationError) {
+					this.$showToast('一年后期待分不得低于现状评分,请注意!');
+					return;
+				}
+				if (this.currentIndex < this.list.length - 1) {
+					this.currentIndex++;
+					this.scrollTop = 0;
+					return;
+				}
+				this.confirmSubmit();
+			},
+			confirmSubmit() {
 				if (this.isSubmitting) return;
 			
 				let firstUnansweredIndex = -1;
@@ -260,17 +310,9 @@
 				});
 			
 				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; // 终止提交
 				}
 
@@ -281,12 +323,9 @@
 					if (error && firstInvalidExpectationIndex === -1) firstInvalidExpectationIndex = i;
 				});
 				if (firstInvalidExpectationIndex > -1) {
-					uni.showModal({
-						title: '提示',
-						content: '一年后期待分不得低于现状评分,请注意!',
-						showCancel: false,
-						success: res => { if (res.confirm) this.scrollToQuestion(firstInvalidExpectationIndex); }
-					});
+					this.currentIndex = firstInvalidExpectationIndex;
+					this.scrollTop = 0;
+					this.$showToast('一年后期待分不得低于现状评分,请注意!');
 					return;
 				}
 			
@@ -380,7 +419,35 @@
 			}
 		}
 	}
-</script>
+</script>
+
+<style scoped lang="scss">
+	.question-nav {
+		flex: 1;
+		gap: 20rpx;
+		.question-nav-btn {
+			flex: 1;
+			height: 88rpx;
+			border-radius: 44rpx;
+			line-height: 88rpx;
+			text-align: center;
+			font-size: 30rpx;
+			font-weight: bold;
+			&.primary {
+				background: #833478;
+				color: #FFFFFF;
+			}
+			&.secondary {
+				background: #FFFFFF;
+				border: 2rpx solid #833478;
+				color: #833478;
+			}
+			&.disabled {
+				opacity: .5;
+			}
+		}
+	}
+</style>
 
 <style scoped lang="scss">
 	.loading-container {

+ 16 - 1
utils/backgroundSurvey.js

@@ -22,10 +22,24 @@ function createBackgroundAnswerPayload(question, optionCode, customText) {
 function encodeQuery(params) {
 	return Object.keys(params || {})
 		.filter(key => params[key] !== undefined && params[key] !== null && params[key] !== '')
-		.map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
+		.map(key => `${encodeURIComponent(key)}=${encodeURIComponent(decodeQueryValue(params[key]))}`)
 		.join('&')
 }
 
+function decodeQueryValue(value) {
+	let decoded = String(value == null ? '' : value)
+	for (let i = 0; i < 5; i += 1) {
+		try {
+			const next = decodeURIComponent(decoded)
+			if (next === decoded) break
+			decoded = next
+		} catch (error) {
+			break
+		}
+	}
+	return decoded
+}
+
 function backgroundIntroUrl(params) {
 	return `/pagesPublish/backgroundSurveyIntro?${encodeQuery(Object.assign({ stage: 'background' }, params))}`
 }
@@ -48,6 +62,7 @@ module.exports = {
 	validateBackgroundAnswer,
 	createBackgroundAnswerPayload,
 	encodeQuery,
+	decodeQueryValue,
 	backgroundIntroUrl,
 	perillIntroUrl,
 	questionnaireFillUrl,