dedsudiyu 6 days ago
parent
commit
6cecfdd98e

+ 146 - 0
pages_safetyEducationExamination/utils/index.js

@@ -0,0 +1,146 @@
+import {
+	examUserExamStart,
+	examUserExamCommitmentConfirm,
+} from '@/pages_safetyEducationExamination/api/index.js'
+
+/**
+ * 考试入口统一处理
+ * @param {Object} item  考试任务数据
+ * @param {Object} callbacks  { openCommitmentDialog }  —— 需要显示承诺书时的回调
+ */
+export async function goToExamPage(item, callbacks = {}) {
+
+	if (item.conditionType == 1) {
+		if (item.examStudy && item.courseId) {
+			// 学习课程 — 等待后续逻辑
+		} else {
+			if (item.knowledgePointIds && item.knowledgePointIds.length > 0) {
+				const ids = Array.isArray(item.knowledgePointIds)
+					? item.knowledgePointIds.join(',')
+					: item.knowledgePointIds;
+				uni.navigateTo({
+					url: `/pages_safetyEducationExamination/views/studyHourTask/index?knowledgePointId=${ids}`,
+				});
+			} else {
+				uni.navigateTo({ url: '/pages_safetyEducationExamination/views/study/index' });
+			}
+		}
+
+	} else if (item.conditionType == 2) {
+		// 学习课程 — 等待后续逻辑
+
+	} else if (item.conditionType == 3) {
+		if (item.mockExamId) {
+			const examData = encodeURIComponent(JSON.stringify(item));
+			uni.navigateTo({
+				url: `/pages_safetyEducationExamination/views/exam/mockExamInfo?examData=${examData}`,
+			});
+		} else {
+			try {
+				const { data } = await examUserExamStart({ examId: item.examId, examScene: 2 });
+				if (data.code === 200 && data.data && data.data.attemptId) {
+					const filled = { ...item, attemptId: data.data.attemptId };
+					const examData = encodeURIComponent(JSON.stringify(filled));
+					uni.navigateTo({
+						url: `/pages_safetyEducationExamination/views/exam/mockExamInfo?examData=${examData}`,
+					});
+				} else {
+					uni.showToast({ title: data.message || '获取模拟试卷失败', icon: 'none' });
+				}
+			} catch (e) {
+				console.error('获取模拟试卷失败', e);
+				uni.showToast({ title: '获取模拟试卷失败', icon: 'none' });
+			}
+		}
+
+	} else if (item.conditionType == 4) {
+		await resolveExamEntry(item, callbacks);
+	}
+}
+
+/**
+ * 判断是否需要承诺书,并决定后续跳转
+ * @param {Object} item       考试任务数据
+ * @param {Object} callbacks  { openCommitmentDialog(item) }
+ */
+export async function resolveExamEntry(item, callbacks = {}) {
+	if (item.commitmentEnabled == 1 && !item.commitmentConfirmed) {
+		// 需要展示承诺书弹窗,交由调用方组件处理
+		if (typeof callbacks.openCommitmentDialog === 'function') {
+			callbacks.openCommitmentDialog(item);
+		}
+	} else {
+		// 不需要承诺书,直接进入考试
+		await startFormalExam(item);
+	}
+}
+
+/**
+ * 确认承诺书并进入考试(由组件点击"确认"按钮时调用)
+ * @param {Object} preData    当前承诺书对应的考试数据
+ * @param {Function} onClose  承诺确认成功后关闭弹窗的回调
+ */
+export async function confirmCommitmentAndStart(preData, onClose) {
+	let attemptId = preData.attemptId;
+
+	if (!attemptId) {
+		try {
+			const { data } = await examUserExamStart({ examId: preData.examId, examScene: 1 });
+			if (data.code === 200 && data.data && data.data.attemptId) {
+				attemptId = data.data.attemptId;
+			} else {
+				uni.showToast({ title: data.message || '开始考试失败', icon: 'none' });
+				return;
+			}
+		} catch (e) {
+			console.error('开始考试失败', e);
+			uni.showToast({ title: '开始考试失败', icon: 'none' });
+			return;
+		}
+	}
+
+	try {
+		const { data } = await examUserExamCommitmentConfirm({ attemptId });
+		if (data.code === 200) {
+			if (typeof onClose === 'function') onClose();
+			navigateToExamPlay(preData.examId, attemptId, preData.examKind);
+		} else {
+			uni.showToast({ title: data.message || '确认失败', icon: 'none' });
+		}
+	} catch (e) {
+		console.error('确认承诺书失败', e);
+		uni.showToast({ title: '确认失败', icon: 'none' });
+	}
+}
+
+/**
+ * 发起或续考正式考试
+ * @param {Object} item  考试任务数据(含 examId / attemptId / examKind)
+ */
+export async function startFormalExam(item) {
+	let attemptId = item.attemptId;
+	if (!attemptId) {
+		try {
+			const { data } = await examUserExamStart({ examId: item.examId, examScene: 1 });
+			if (data.code !== 200 || !data.data || !data.data.attemptId) {
+				uni.showToast({ title: data.message || '开始考试失败', icon: 'none' });
+				return;
+			}
+			attemptId = data.data.attemptId;
+		} catch (e) {
+			console.error('开始考试失败', e);
+			uni.showToast({ title: '开始考试失败', icon: 'none' });
+			return;
+		}
+	}
+	navigateToExamPlay(item.examId, attemptId, item.examKind);
+}
+
+/**
+ * 跳转到答题页
+ */
+export function navigateToExamPlay(examId, attemptId, examKind) {
+	uni.navigateTo({
+		url: `/pages_safetyEducationExamination/views/exam/onlineExamPlay?examId=${encodeURIComponent(examId)}&attemptId=${encodeURIComponent(attemptId)}&examKind=${encodeURIComponent(examKind || '')}`,
+	});
+}

+ 111 - 45
pages_safetyEducationExamination/views/exam/onlineExamInfo.vue

@@ -57,6 +57,23 @@
 				{{examData.needStudy||examData.examStudy?'开始学习':(examData.mockExam?'开始模拟考试':'开始考试')}}
 				{{examData.needStudy||examData.examStudy?'开始学习':(examData.mockExam?'开始模拟考试':'开始考试')}}
 				</view>
 				</view>
 		</view>
 		</view>
+		<!-- 考试承诺书弹窗 -->
+		<uni-popup ref="preExamDialog" type="center" :mask-click="false">
+			<view class="pre-exam-dialog">
+				<view class="dialog-header">
+					<text class="dialog-title">考试承诺书</text>
+				</view>
+				<view class="dialog-body">
+					<scroll-view scroll-y class="content-scroll">
+						<richTextPdf ref="richTextPdf" :content="richTextHtml" />
+					</scroll-view>
+				</view>
+				<view class="dialog-footer">
+					<view v-if="preButtonType" class="btn btn-border" @click="downloadCommitment">下载</view>
+					<view class="btn btn-primary" @click="confirmCommitment">确认</view>
+				</view>
+			</view>
+		</uni-popup>
 	</view>
 	</view>
 </template>
 </template>
 
 
@@ -65,13 +82,24 @@
 		parseTime
 		parseTime
 	} from '@/component/public.js'
 	} from '@/component/public.js'
 	import {
 	import {
-		examUserExamStart
-	} from '@/pages_safetyEducationExamination/api/index.js'
+		goToExamPage,
+		confirmCommitmentAndStart,
+		startFormalExam,
+	} from '@/pages_safetyEducationExamination/utils/index.js'
+	import richTextPdf from '@/pages_safetyEducationExamination/component/richTextPdf.vue'
 
 
 	export default {
 	export default {
+		components: {
+			richTextPdf
+		},
 		data() {
 		data() {
 			return {
 			return {
 				examData: {},
 				examData: {},
+				// 承诺书相关
+				preButtonType: false,
+				richTextHtml: '',
+				preData: null,
+				itemData:{},
 			}
 			}
 		},
 		},
 		computed: {
 		computed: {
@@ -112,54 +140,37 @@
 					});
 					});
 				}
 				}
 			},
 			},
-			goToCourse() {
-				// 跳转到课程学习页面
-				uni.showToast({
-					title: '跳转到课程学习',
-					icon: 'none'
+			async startExam() {
+				this.$set(this,'itemData',this.examData);
+				goToExamPage(this.examData, {
+					openCommitmentDialog: (examItem) => {
+						this.preButtonType = examItem.commitmentPrintEnabled == 1;
+						this.richTextHtml = examItem.commitmentContent;
+						this.preData = examItem;
+						this.$refs.preExamDialog.open();
+					},
 				});
 				});
 			},
 			},
-			goToMockExam() {
-				// 跳转到模拟考试页面
-				uni.showToast({
-					title: '跳转到模拟考试',
-					icon: 'none'
+			// 下载承诺书
+			downloadCommitment() {
+				uni.showToast({ title: '正在下载,请耐心等候', icon: 'none' });
+				this.$refs.richTextPdf.downloadPDF();
+			},
+			// 确认承诺书
+			async confirmCommitment() {
+				await confirmCommitmentAndStart(this.preData, () => {
+					this.$refs.preExamDialog.close();
+					startFormalExam(this.itemData);
 				});
 				});
 			},
 			},
-			async startExam() {
-				if (!this.examData.available) {
-					uni.showToast({
-						title: this.examData.unavailableDesc || '暂不可考试',
-						icon: 'none'
-					});
-					return;
-				}
-
-				let attemptId = this.examData.attemptId;
-				if (!attemptId) {
-					try {
-						const { data } = await examUserExamStart({
-							examId: this.examData.examId,
-							examScene: 1
-						});
-						if (data.code !== 200 || !data.data || !data.data.attemptId) {
-							uni.showToast({
-								title: data.message || '开始考试失败',
-								icon: 'none'
-							});
-							return;
-						}
-						attemptId = data.data.attemptId;
-					} catch (e) {
-						console.error('开始考试失败', e);
-						uni.showToast({ title: '开始考试失败', icon: 'none' });
-						return;
+			// 获取任务列表
+			async loadTaskList() {
+				try {
+					const { data } = await examUserExamStudyTaskList({ page: 1, pageSize: 1, examStatus: 2, isSpecialExam: false });
+					if (data.code === 200) {
+						this.$set(this, 'onlineExamList', data.data.records);
 					}
 					}
-				}
-
-				uni.navigateTo({
-					url: `/pages_safetyEducationExamination/views/exam/onlineExamPlay?examId=${encodeURIComponent(this.examData.examId)}&attemptId=${encodeURIComponent(attemptId)}&examKind=${encodeURIComponent(this.examData.examKind || '')}`
-				});
+				} catch (e) { console.error('获取考试任务失败', e); }
 			},
 			},
 		},
 		},
 	}
 	}
@@ -356,4 +367,59 @@
 		font-size: 32rpx;
 		font-size: 32rpx;
 		font-weight: 600;
 		font-weight: 600;
 	}
 	}
+	// 承诺书弹窗样式
+	.pre-exam-dialog {
+		width: 600rpx;
+		max-height: 80vh;
+		background: #fff;
+		border-radius: 20rpx;
+		overflow: hidden;
+	}
+
+	.dialog-header {
+		padding: 32rpx;
+		border-bottom: 1rpx solid #eee;
+
+		.dialog-title {
+			font-size: 32rpx;
+			font-weight: 600;
+			color: #333;
+		}
+	}
+
+	.dialog-body {
+		height: 800rpx;
+		overflow: hidden;
+
+		.content-scroll {
+			height: 100%;
+		}
+	}
+
+	.dialog-footer {
+		display: flex;
+		gap: 20rpx;
+		padding: 24rpx 32rpx;
+		border-top: 1rpx solid #eee;
+
+		.btn {
+			flex: 1;
+			height: 72rpx;
+			line-height: 72rpx;
+			text-align: center;
+			font-size: 28rpx;
+			border-radius: 12rpx;
+		}
+
+		.btn-border {
+			background: #fff;
+			color: #1857d4;
+			border: 1rpx solid #1857d4;
+		}
+
+		.btn-primary {
+			background: #1857d4;
+			color: #fff;
+		}
+	}
 </style>
 </style>

+ 30 - 173
pages_safetyEducationExamination/views/home/component/examTask.vue

@@ -45,9 +45,12 @@
 <script>
 <script>
 	import {
 	import {
 		examUserExamStudyTaskList,
 		examUserExamStudyTaskList,
-		examUserExamStart,
-		examUserExamCommitmentConfirm,
 	} from '@/pages_safetyEducationExamination/api/index.js'
 	} from '@/pages_safetyEducationExamination/api/index.js'
+	import {
+		goToExamPage,
+		confirmCommitmentAndStart,
+		startFormalExam,
+	} from '@/pages_safetyEducationExamination/utils/index.js'
 	import richTextPdf from '@/pages_safetyEducationExamination/component/richTextPdf.vue'
 	import richTextPdf from '@/pages_safetyEducationExamination/component/richTextPdf.vue'
 
 
 	export default {
 	export default {
@@ -58,197 +61,51 @@
 			return {
 			return {
 				onlineExamList: [],
 				onlineExamList: [],
 				// 承诺书相关
 				// 承诺书相关
-				preExamDialogType: false,
 				preButtonType: false,
 				preButtonType: false,
 				richTextHtml: '',
 				richTextHtml: '',
 				preData: null,
 				preData: null,
+				itemData:{},
 			}
 			}
 		},
 		},
-		created() {
-
-		},
 		mounted() {
 		mounted() {
-			this.examUserExamStudyTaskList();
+			this.loadTaskList();
 		},
 		},
 		methods: {
 		methods: {
-			goToPage(type,item){
-				if(type == 1){
-					//考试列表
-					uni.navigateTo({
-						url: '/pages_safetyEducationExamination/views/exam/index',
-					});
-				}else if(type == 2){
-					//开始考试相关业务
-					if(item.conditionType == 1){
-						if(item.examStudy&&item.courseId){
-							//学习课程
-							let obj = {
-								courseId: item.courseId,
-								examId: item.examId,
-							}
-							//等待后续逻辑
-						}else{
-							//学时要求
-							if(item.knowledgePointIds){
-								//学时知识点
-								uni.navigateTo({
-									url: `/pages_safetyEducationExamination/views/studyHourTask/index?knowledgePointId=${item.knowledgePointIds}`,
-								});
-							}else{
-								//无知识点要求
-								uni.navigateTo({
-									url: '/pages_safetyEducationExamination/views/study/index',
-								});
-							}
-						}
-					}else if(item.conditionType == 2){
-						//学习课程
-						let obj = {
-							courseId: item.courseId,
-							examId: item.examId,
-						}
-						//等待后续逻辑
-					}else if(item.conditionType == 3){
-						//模拟考试
-						if(item.mockExamId){
-							let obj = {
-								examId: item.examId,
-								attemptId: item.mockExamId,
-							}
-							//等待后续逻辑
-						}else{
-							this.examUserExamStart({examId:item.examId,examScene:2});
-						}
-					}else if(item.conditionType == 4){
-						//开始考试
-					}
-				}
-			},
-			//模拟考试获取试卷
-			async examUserExamStart(obj) {
-				try {
-					const { data } = await examUserExamStart(obj);
-					if (data.code === 200) {
-						let obj = {
-							examId: item.examId,
-							attemptId: response.data.attemptId,
-						}
-						//等待后续逻辑
-					}
-				} catch (e) { console.error('模拟考试获取试卷失败', e); }
-			},
-			//开始考试判断是否有承诺书
-			setRichExamData(item){
-				if(item.commitmentEnabled == 1 && !item.commitmentConfirmed){
-					//富文本弹窗考试承诺书
-					this.preButtonType = item.commitmentPrintEnabled == 1;
-					this.richTextHtml = item.commitmentContent;
-					this.preData = item;
-					this.$refs.preExamDialog.open();
+			goToPage(type, item) {
+				if (type == 1) {
+					uni.navigateTo({ url: '/pages_safetyEducationExamination/views/exam/index' });
+					return;
 				}else{
 				}else{
-					if(item.attemptId){
-						//上次考试未完成继续考试
-						let obj = {
-							attemptId: item.attemptId,
-							type: '1',
-							examKind:item.examKind,
-						}
-						//等待后续逻辑
-					}else{
-						//开始新考试
-						this.startNewExam(item);
-					}
+					this.$set(this,'itemData',item);
+					goToExamPage(item, {
+						openCommitmentDialog: (examItem) => {
+							this.preButtonType = examItem.commitmentPrintEnabled == 1;
+							this.richTextHtml = examItem.commitmentContent;
+							this.preData = examItem;
+							this.$refs.preExamDialog.open();
+						},
+					});
 				}
 				}
+				
 			},
 			},
 			// 下载承诺书
 			// 下载承诺书
 			downloadCommitment() {
 			downloadCommitment() {
-				uni.showToast({
-					title: '正在下载,请耐心等候',
-					icon: 'none'
-				});
+				uni.showToast({ title: '正在下载,请耐心等候', icon: 'none' });
 				this.$refs.richTextPdf.downloadPDF();
 				this.$refs.richTextPdf.downloadPDF();
 			},
 			},
 			// 确认承诺书
 			// 确认承诺书
 			async confirmCommitment() {
 			async confirmCommitment() {
-				if (this.preData.attemptId) {
-					await this.confirmAndStart(this.preData.attemptId);
-				} else {
-					try {
-						const { data } = await examUserExamStart({
-							examId: this.preData.examId,
-							examScene: 1
-						});
-						if (data.code === 200 && data.data.attemptId) {
-							await this.confirmAndStart(data.data.attemptId);
-						} else {
-							uni.showToast({
-								title: data.message || '开始考试失败',
-								icon: 'none'
-							});
-						}
-					} catch (e) {
-						console.error('开始考试失败', e);
-						uni.showToast({
-							title: '开始考试失败',
-							icon: 'none'
-						});
-					}
-				}
-			},
-			// 确认承诺并开始考试
-			async confirmAndStart(attemptId) {
-				try {
-					const { data } = await examUserExamCommitmentConfirm({ attemptId });
-					if (data.code === 200) {
-						this.$refs.preExamDialog.close();
-						// 跳转到考试页面
-						let obj = {
-							examId: this.preData.examId,
-							attemptId: attemptId,
-							type: '1',
-							examKind: this.preData.examKind,
-						};
-						// 等待后续逻辑:跳转到答题页面
-						uni.showToast({
-							title: '已确认承诺书',
-							icon: 'success'
-						});
-					}
-				} catch (e) {
-					console.error('确认承诺书失败', e);
-					uni.showToast({
-						title: '确认失败',
-						icon: 'none'
-					});
-				}
-			},
-			//开始考试
-			async examUserExamStart(item) {
-				try {
-					let obj = {examId:item.examId,examScene:1};
-					const { data } = await examUserExamStart(obj);
-					if (data.code === 200) {
-						let obj = {
-							examId: item.examId,
-							attemptId: data.data.attemptId,
-							type: '1',
-							examKind:item.examKind,
-						}
-						//等待后续逻辑
-					}
-				} catch (e) { console.error('开始考试失败', e); }
-			},
-			// 开始新考试
-			async startNewExam(item) {
-				await this.examUserExamStart(item);
+				await confirmCommitmentAndStart(this.preData, () => {
+					this.$refs.preExamDialog.close();
+					startFormalExam(this.itemData);
+				});
 			},
 			},
-			//获取任务列表
-			async examUserExamStudyTaskList() {
+			// 获取任务列表
+			async loadTaskList() {
 				try {
 				try {
-					let obj = { page: 1, pageSize: 1, examStatus: 2, isSpecialExam: false };
-					const { data } = await examUserExamStudyTaskList(obj);
+					const { data } = await examUserExamStudyTaskList({ page: 1, pageSize: 1, examStatus: 2, isSpecialExam: false });
 					if (data.code === 200) {
 					if (data.code === 200) {
-						this.$set(this,'onlineExamList',data.data.records);
+						this.$set(this, 'onlineExamList', data.data.records);
 					}
 					}
 				} catch (e) { console.error('获取考试任务失败', e); }
 				} catch (e) { console.error('获取考试任务失败', e); }
 			},
 			},

+ 114 - 2
pages_safetyEducationExamination/views/home/component/specialExam.vue

@@ -42,6 +42,24 @@
 				</view>
 				</view>
 			</view>
 			</view>
 		</view>
 		</view>
+		
+		<!-- 考试承诺书弹窗 -->
+		<uni-popup ref="preExamDialog" type="center" :mask-click="false">
+			<view class="pre-exam-dialog">
+				<view class="dialog-header">
+					<text class="dialog-title">考试承诺书</text>
+				</view>
+				<view class="dialog-body">
+					<scroll-view scroll-y class="content-scroll">
+						<richTextPdf ref="richTextPdf" :content="richTextHtml" />
+					</scroll-view>
+				</view>
+				<view class="dialog-footer">
+					<view v-if="preButtonType" class="btn btn-border" @click="downloadCommitment">下载</view>
+					<view class="btn btn-primary" @click="confirmCommitment">确认</view>
+				</view>
+			</view>
+		</uni-popup>
 	</view>
 	</view>
 </template>
 </template>
 
 
@@ -49,11 +67,20 @@
 	import { 
 	import { 
 		examUserExamStudyTaskList, 
 		examUserExamStudyTaskList, 
 	} from '@/pages_safetyEducationExamination/api/index.js'
 	} from '@/pages_safetyEducationExamination/api/index.js'
+	import richTextPdf from '@/pages_safetyEducationExamination/component/richTextPdf.vue'
 	export default {
 	export default {
+		components: {
+			richTextPdf
+		},
 		data() {
 		data() {
 			return {
 			return {
 				examType:true,
 				examType:true,
 				examData:{},
 				examData:{},
+				// 承诺书相关
+				preButtonType: false,
+				richTextHtml: '',
+				preData: null,
+				itemData:{},
 			}
 			}
 		},
 		},
 		created() {
 		created() {
@@ -63,8 +90,37 @@
 			this.examUserExamStudyTaskList();
 			this.examUserExamStudyTaskList();
 		},
 		},
 		methods: {
 		methods: {
-			tableButton(type,item){
-				
+			goToPage(item) {
+				this.$set(this,'itemData',this.examData);
+				goToExamPage(this.examData, {
+					openCommitmentDialog: (examItem) => {
+						this.preButtonType = examItem.commitmentPrintEnabled == 1;
+						this.richTextHtml = examItem.commitmentContent;
+						this.preData = examItem;
+						this.$refs.preExamDialog.open();
+					},
+				});
+			},
+			// 下载承诺书
+			downloadCommitment() {
+				uni.showToast({ title: '正在下载,请耐心等候', icon: 'none' });
+				this.$refs.richTextPdf.downloadPDF();
+			},
+			// 确认承诺书
+			async confirmCommitment() {
+				await confirmCommitmentAndStart(this.preData, () => {
+					this.$refs.preExamDialog.close();
+					startFormalExam(this.itemData);
+				});
+			},
+			// 获取任务列表
+			async loadTaskList() {
+				try {
+					const { data } = await examUserExamStudyTaskList({ page: 1, pageSize: 1, examStatus: 2, isSpecialExam: false });
+					if (data.code === 200) {
+						this.$set(this, 'onlineExamList', data.data.records);
+					}
+				} catch (e) { console.error('获取考试任务失败', e); }
 			},
 			},
 			async examUserExamStudyTaskList() {
 			async examUserExamStudyTaskList() {
 				try {
 				try {
@@ -159,4 +215,60 @@
 		}
 		}
 		
 		
 	}
 	}
+	
+	// 承诺书弹窗样式
+	.pre-exam-dialog {
+		width: 600rpx;
+		max-height: 80vh;
+		background: #fff;
+		border-radius: 20rpx;
+		overflow: hidden;
+	}
+	
+	.dialog-header {
+		padding: 32rpx;
+		border-bottom: 1rpx solid #eee;
+	
+		.dialog-title {
+			font-size: 32rpx;
+			font-weight: 600;
+			color: #333;
+		}
+	}
+	
+	.dialog-body {
+		height: 800rpx;
+		overflow: hidden;
+	
+		.content-scroll {
+			height: 100%;
+		}
+	}
+	
+	.dialog-footer {
+		display: flex;
+		gap: 20rpx;
+		padding: 24rpx 32rpx;
+		border-top: 1rpx solid #eee;
+	
+		.btn {
+			flex: 1;
+			height: 72rpx;
+			line-height: 72rpx;
+			text-align: center;
+			font-size: 28rpx;
+			border-radius: 12rpx;
+		}
+	
+		.btn-border {
+			background: #fff;
+			color: #1857d4;
+			border: 1rpx solid #1857d4;
+		}
+	
+		.btn-primary {
+			background: #1857d4;
+			color: #fff;
+		}
+	}
 </style>
 </style>