两天肝出刷题小程序---AI识图生诗词文案(欢迎互踩)小程序端

有个朋友要考2024年上海三类人员安管考试B证,他手里是一个word试题文档。需要打印出来在背,很麻烦。但是由于是太专业太新的试题,在网上没有类似的小程序。所以我利用两天时间在现有小程序(AI识图生诗词文案)基础上增加了一个刷题页面。

先给自己的小程序曝光一下,欢迎各位大佬光临!扫码或搜索AI识图生诗词文案

书接上文,上一篇写了django实现刷题题库及访问视图的功能,前端给后端传递题号,后端给前端返回试题、选项、答案等信息。

小程序页功能有显示题目、显示选项、用户回答完后显示答案、显示正确或错误的图标、记录用户正确题数量和错误题数量、翻页和滑动翻页、跳转题目、记录用户上次访问的题号等功能。

先上图片看看效果

代码写的如果有问题,也请各位大佬指正。谢谢!

下面写小程序端如何实现(我使用vscode和uniapp写的小程序)。

<template>
	<view class="page-content" @touchstart="onTouchStart" @touchend="onTouchEnd" style="height: 100%;">
		<!-- 显示题目 -->
		<uni-card :is-shadow="false" style="background-color: transparent;">
			<text class="uni-body">{{ type }}.第{{ questionid }}题,共{{ maxquestions }}题</text>
		</uni-card>
		<uni-card class="question">
			<text>{{ question }}</text>
		</uni-card>
		<!-- 正确或错误的邮戳 -->
		<view class="question">
			<view v-if="hasAnswered" class="stamp-container">
				<img :src="stampImageUrl" class="stamp-image" />
			</view>
		</view>
		<!-- 显示选项,选项前加上字母 -->

		<uni-card>
			<uni-data-checkbox multiple mode="list" v-model="selectedOptions" :localdata="formattedOptionsWithLetters"
				:disabled="hasAnswered"></uni-data-checkbox>
		</uni-card>


		<!-- 提交按钮 -->
		<view class="submit">
			<button @click="submitAnswer" :disabled="hasAnswered">提交</button>
		</view>

		<!-- 显示我的答案和正确答案 -->
		<view class="answer" v-if="hasAnswered">
			<uni-row class="demo-uni-row" :width="nvueWidth">
				<uni-col :span="12">
					<view class="demo-uni-col correct">正确答案:{{ correctAnswersLetters }}</view>
				</uni-col>
				<uni-col :span="12">
					<view class="demo-uni-col">我的答案:{{ selectedOptionsLetters.join(', ') }}</view>
				</uni-col>
			</uni-row>
		</view>

		<!-- 显示正确题目和错误题目的数量 -->
		<view class="answer">
			<uni-row class="demo-uni-row" :width="nvueWidth">
				<uni-col :span="12">
					<view class="demo-uni-col dark">正确题目:{{ correctCount }}</view>
				</uni-col>
				<uni-col :span="12">
					<view class="demo-uni-col light">错误题目:{{ wrongCount }}</view>
				</uni-col>
			</uni-row>
		</view>
		<!-- 添加左右翻页按钮 -->
		<view class="fixed-pagination">
			<button @click="changeQuestion(-1)">上一题</button>
			<input type="number" v-model="inputQuestionId" placeholder="输入页码" />
			<button @click="goToQuestion">跳转</button>
			<button @click="changeQuestion(1)">下一题</button>
		</view>
	</view>
</template>
<script>
import {
	mapState, mapMutations
} from 'vuex'
export default {
	data() {
		return {
			questionid: 1,
			type: '',
			question: '',
			options: [],
			answer: [],
			maxquestions: 800,//最大题目数量
			selectedOptions: [], // 用户选择的选项
			answerkey: '', // 正确答案的索引
			selectedOptionLetter: '', // 用户选择的选项字母
			correctCount: 0, // 正确题目数量
			wrongCount: 0, // 错误题目数量
			touchStartX: 0, // 记录触摸开始的X坐标
			touchEndX: 0, // 记录触摸结束的X坐标
			inputQuestionId: '', // 用户输入的题目编号
			hasAnswered: false, // 用户是否已经回答了当前题目
			isCorrect: false, // 用户的回答是否正确
			stampImageUrl: '', // 用于显示邮戳的图片路径
		}
	},
	computed: {
		...mapState(['isAuth',]),
		// 格式化选项以符合uni-data-checkbox的数据格式,并添加字母
		formattedOptionsWithLetters() {
			return this.options.map((option, index) => ({ value: index, text: `${this.getOptionLetter(index)}: ${option}` }));
		},
		// 获取用户选择的选项的字母表示
		selectedOptionsLetters() {
			return this.selectedOptions.map(index => this.getOptionLetter(index));
		},
		// 获取正确答案的字母表示
		correctAnswersLetters() {
			if (!this.answer || this.answer.length === 0) {
				return ''; // 如果答案为空,返回空字符串
			}
			// 将正确答案的文本转换为索引
			const correctAnswerIndexes = this.answer.map(answerText =>
				this.options.findIndex(option => option === answerText)
			);
			// 过滤掉未找到的索引(即 findIndex 返回 -1 的情况)
			const filteredCorrectAnswerIndexes = correctAnswerIndexes.filter(index => index !== -1);
			// 将索引转换为字母表示
			return filteredCorrectAnswerIndexes.map(index => this.getOptionLetter(index)).join(', ');
		},
	},
	mounted() {
		this.getQuestion();
	},
	methods: {
		...mapMutations(['saveLoginStatus', 'saveUserInfo']),
		// 首先获取上次访问的试题ID
		getLastVisitedQuestion() {
			const token = uni.getStorageSync('token');
			const header = {
				'Authorization': `Bearer ${token}`,
			};
			this.$api.create.getlastvisitedquestion({}, { header }).then(response => {
				// 成功获取后,取得singlequestion的questionid,更新this.questionid
				this.questionid = parseInt(response.data.multiplequestion.questionid);
				// 请求新的试题
				this.getQuestion();
			}).catch(error => {
				// 如果获取失败,可能是用户第一次使用,直接请求第一题
				console.error(error);
				this.questionid = 1;
				this.getQuestion();
			});
		},
		// 获取试题
		getQuestion() {
			const token = uni.getStorageSync('token');
			const data = {
				questionid: this.questionid,
			};

			const header = {
				'Authorization': `Bearer ${token}`,
			};
			this.$api.create.getmultipleQuestions(data, { header }).then(response => {
				this.question = response.data.question;
				this.options = response.data.options;
				this.answer = response.data.answer; // 确保 answer 是字符串
				this.type = response.data.type;
				this.maxquestions = response.data.total_questions;
				// 成功获取试题后,保存新的questionid到后端
				this.saveLastVisitedQuestion(this.questionid);
				// 重置用户选择和显示答案的状态
				this.selectedOptions = [];
				this.isCorrect = false;
				this.hasAnswered = false;
				this.stampImageUrl = ''; // 重置邮戳图片路径
			}).catch(error => {
				// 处理错误
				console.error(error);
				uni.showToast({
					title: '没有这道题哦!',
					icon: 'none',
					duration: 2000
				});
			});
		},
		// 保存最新访问的试题ID到后端
		saveLastVisitedQuestion(questionId) {
			const token = uni.getStorageSync('token');
			const data = {
				type: 'multiplequestion', // 根据你的需求调整
				questionid: questionId,
			};
			const header = {
				'Authorization': `Bearer ${token}`,
			};
			this.$api.create.savelastvisitedquestion(data, { header }).then(response => {
				// console.log('题号保存成功', response);
			}).catch(error => {
				console.error('题号保存失败', error);
			});
		},
		// 获取选项的字母
		getOptionLetter(key) {
			const letters = ['A', 'B', 'C', 'D', 'E'];
			return letters[key];
		},

		// 提交答案的逻辑
		submitAnswer() {
			this.hasAnswered = true;
			// 将正确答案的文本转换为索引
			const correctAnswerIndexes = this.answer.map(answerText =>
				this.options.findIndex(option => option === answerText)
			);
			// 转换用户答案和正确答案为基于索引的字符串
			const userAnswerSorted = this.selectedOptions.map(Number).sort().join(',');
			const correctAnswerSorted = correctAnswerIndexes.sort().join(',');
			if (userAnswerSorted === correctAnswerSorted) {
				this.correctCount++;
				this.isCorrect = true; // 设置回答正确
				this.stampImageUrl = '/static/zhengque.svg';
			} else {
				this.wrongCount++;
				//添加错题
				this.addwrongBook(this.questionid);
				this.isCorrect = false; // 设置回答错误
				this.stampImageUrl = '/static/cuowu.svg';
			}
		},
		// 添加错题,其他题型需要修改type
		addwrongBook(questionid, type) {
			const token = uni.getStorageSync('token');
			const data = {
				questionid: questionid,
				type: 'multiplequestion',
			};

			const header = {
				'Authorization': `Bearer ${token}`,
			};
			this.$api.create.addwrongBook(data, { header }).then(response => {
				// console.log(response.data);
			}).catch(error => {
				console.error(error);
			});
		},
		// 登录
		async wechatLogin() {
			try {
				const loginRes = await uni.login({ provider: 'weixin' });
				const userInfoRes = await uni.getUserInfo({ provider: 'weixin' });
				const userInfo = userInfoRes.userInfo;
				this.code = loginRes[1].code;
				this.doLogin();
			} catch (err) {
				console.log('微信登录失败', err);
			}
		},
		async doLogin() {
			try {
				const response = await this.$api.user.login({ code: this.code });
				if (response.statusCode === 200) {
					console.log('登录成功!');
					// 保存用户信息和token
					this.saveLoginStatus(response.data);
				}
			} catch (error) {
				console.log('登录失败', error);
			}
		},
		// 触摸开始事件
		onTouchStart(event) {
			this.touchStartX = event.changedTouches[0].clientX;
		},
		// 触摸结束事件
		onTouchEnd(event) {
			this.touchEndX = event.changedTouches[0].clientX;
			this.handleSwipe();
		},
		// 处理滑动事件
		handleSwipe() {
			const threshold = 50; // 设定滑动阈值
			const deltaX = this.touchEndX - this.touchStartX;
			if (deltaX > threshold) {
				// 向右滑动,显示上一题
				this.changeQuestion(-1);
			} else if (deltaX < -threshold) {
				// 向左滑动,显示下一题
				this.changeQuestion(1);
			}
		},
		// 修改后的changeQuestion方法
		changeQuestion(direction) {
			const newQuestionId = this.questionid + direction;
			const maxquestions = this.maxquestions;
			if (newQuestionId < 1) {
				uni.showToast({
					title: '已经是第一题了',
					icon: 'none'
				});
				return;
			}

			if (newQuestionId > maxquestions) {
				uni.showToast({
					title: '已经是最后一题了',
					icon: 'none'
				});
				return;
			}
			// 更新题目编号
			this.questionid = newQuestionId;
			// 获取新题目
			this.getQuestion();
		},

		// 跳转到指定页面
		goToQuestion() {
			const questionId = parseInt(this.inputQuestionId, 10);
			const maxquestions = this.maxquestions;
			if (isNaN(questionId) || questionId < 1) {
				uni.showToast({
					title: '请输入有效的题目编号',
					icon: 'none'
				});
				return;
			}
			if (questionId > maxquestions) {
				uni.showToast({
					title: `超出范围,共${maxquestions}题`,
					icon: 'none'
				});
				return;
			}
			this.questionid = questionId; // 更新题目编号
			this.selectedOption = null;
			this.hasAnswered = false;
			this.isCorrect = false;
			this.stampImageUrl = ''; // 重置邮戳图片路径
			this.getQuestion(); // 获取新题目
			this.inputQuestionId = ''; // 清空输入框
		},

	},
	//加载页面时,执行getData函数
	onLoad() {
		this.getLastVisitedQuestion()
	},
}
</script>

  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值