wangxy 1 month ago
parent
commit
70ccfe1f82

+ 21 - 0
pages.json

@@ -171,6 +171,27 @@
 			{
 				"navigationStyle": "custom"
 			}
+		},
+		{
+			"path" : "pages/chanpinXuanze/my",
+			"style" : 
+			{
+				"navigationStyle": "custom"
+			}
+		},
+		{
+			"path" : "pages/chanpinXuanze/myInfo",
+			"style" : 
+			{
+				"navigationStyle": "custom"
+			}
+		},
+		{
+			"path" : "pages/chanpinXuanze/aboutPage",
+			"style" : 
+			{
+				"navigationStyle": "custom"
+			}
 		}
 	],
 	"tabBar": {

+ 60 - 0
pages/chanpinXuanze/aboutPage.vue

@@ -0,0 +1,60 @@
+<template>
+	<view class="ezy-about-page">
+		<view class="icon-title-navBar-box">
+			<view @click="handleBack" class="nav-bar-icon"></view>
+			<text class="nav-bar-title">关于我们</text>
+		</view>
+		<view class="about-body-border">
+			<view class="about-body-box">
+				<view class="content-top-box">
+					<icon class="about-icon-box"></icon>
+					<view class="top-text-box">
+						<view class="about-name">鹅状元</view>
+						<view class="about-text">客服电话:4001750778</view>
+						<view class="about-text">备案号:辽ICP备15006970号-7A</view>
+					</view>
+				</view>
+				<view class="content-box">
+					<p>鹅状元 APP:点亮孩子成长之路的智慧灯塔</p>
+					<p>专为 6 - 12 岁孩子量身打造的鹅状元 APP 震撼来袭!</p>
+					<p>在这里,学习就像一场奇妙冒险。数学学习不再是难题堆砌,一套独家“秘籍”让知识轻松解锁。从启蒙到进阶的 L1 - L6 阶梯式成长路径,以新颖的“画图策略”为指引,将复杂问题可视化,引领孩子畅游数字海洋。每一道精心挑选的母题都是开启智慧大门的钥匙,牵一发而动全身,让孩子触类旁通,学会举一反三,真正把知识用起来,生活处处皆数学考场。</p>
+					<p>英语学习更是趣味横生。聚焦神奇“发音密码”,带孩子从字母韵律起步,一步步叩响英语世界的大门。沉浸式学习环境,趣味互动游戏贯穿始终,随着学习深入,孩子悄然掌握自然拼读技巧,单词认读、口语表达水到渠成。</p>
+					<p>鹅状元精准锚定孩子成长关键。学习时,它化身启智伙伴,激励孩子自主找答案,点燃思考火苗;还为孩子搭起表达的“舞台”,使其能自信开麦、条理阐述观点。助力孩子在成长路上全速启航,鹅状元 APP 就是那根神奇“魔杖”,帮孩子解锁无限潜力,奔赴美好未来。</p>
+				</view>
+			</view>
+		</view>
+		<CustomTabBar :levelId="levelId" :typeId="typeId" :subjectId="subjectId" :tipFlag="tipFlag"></CustomTabBar>
+	</view>
+</template>
+
+<script setup>
+	import {onLoad} from '@dcloudio/uni-app';
+	import {ref} from "vue";
+	import CustomTabBar from '@/components/custom-tabbar/custom-tabbar.vue';
+	import cacheManager from '@/utils/cacheManager.js';
+	const subjectId = ref(null);//游客使用
+	const levelId = ref(null);//游客使用
+	const typeId = ref(null);//游客使用
+	const tipFlag = ref(null); //游客使用
+	let routerOpt  = ref(false);
+	
+	// 关于我们
+	function handleBack(){
+		uni.redirectTo({
+			url: '/pages/chanpinXuanze/my'
+		});
+	}
+	
+	onLoad((options) => {
+		if(options){
+			routerOpt = options;
+			subjectId.value = options.subjectId
+			typeId.value = options.typeId
+			levelId.value = options.levelId
+			tipFlag.value = options.tipFlag
+		}
+	})
+</script>
+
+<style>
+</style>

+ 301 - 0
pages/chanpinXuanze/components/questionJiexi.vue

@@ -0,0 +1,301 @@
+<template>
+	<view>
+		<uni-popup ref="popupRef" :animation="false" :is-mask-click="false"
+			mask-background-color="rgba(255, 255, 255, 0.6);" class="ezy-popup-width-all">
+			<view class="ezy-dajx-page">
+				<view class="icon-title-navBar-box">
+					<view @click="handleBack" class="nav-bar-icon"></view>
+					<view class="nav-bar-title">单元测试</view>
+				</view>
+				<view class="shiti-frame-box">
+					<view class="dajx-content-box">
+						<!-- 思路分析 -->
+						<view class="slfx-title"></view>
+						<!-- <view class="slfx-content"> {{data.answer}}</view> -->
+						<rich-text class="slfx-content" :nodes="data.answer"></rich-text>
+
+						<!-- 视频讲解 -->
+						<view class="spjj-title"></view>
+						<view class="ezy-video-box">
+							<!-- 这里放视频 ↓ -->
+							<view class="ezy-video" ref="videoContent" id="wgy-player-test" :playAuth="playAuth"
+								:change:playAuth="renderScript.receiveMsg" :videoId="videoId"
+								:change:videoId="renderScript.videoIdFun" :hideFlag="hideFlag"
+								:change:hideFlag="renderScript.hideFlagFun" :seekTime="seekTime"
+								:change:seekTime="renderScript.seekTimeFun">
+							</view>
+						</view>
+					</view>
+				</view>
+			</view>
+		</uni-popup>
+		<uni-popup ref="popupRef2" :animation="false" :is-mask-click="false"
+			mask-background-color="rgba(51, 137, 217, 0.65);">
+			<view class="course-finish-dialog">
+				<view class="text-score">{{credit}}</view>
+				<view class="course-btn-box">
+					<view @click="goBack" class="return-btn"></view>
+					<view @click="goNext" class="continue-btn"></view>
+				</view>
+			</view>
+		</uni-popup>
+	</view>
+</template>
+<script>
+	import {
+		onLoad,
+		onReady
+	} from '@dcloudio/uni-app';
+	import {
+		getVideoAuth,
+	} from "@/api/shipin.js"
+	export default {
+		props: {
+			cardId: {
+				type: [String, Number],
+				default: 1
+			}
+		},
+		data() {
+			return {
+				pageData: null, //上个页面获取的视频参数(视频id)
+				playAuth: "", //播放凭证
+				progressMarkers: [],
+				videoId: "", //阿里云视频id
+				seekTime: '',
+				hideFlag: 'show',
+				data: {},
+			}
+		},
+		onHide() {
+			this.hideFlag = 'hide'
+		},
+		onUnload() {
+			this.hideFlag = 'hide'
+		},
+		methods: {
+			playEnd(data) {
+				plus.screen.lockOrientation('portrait-primary');
+				this.$refs.popupRef2.open();
+			},
+			goBack() {
+				plus.screen.unlockOrientation();
+				this.$refs.popupRef2.close();
+				this.$refs.popupRef.close()
+			},
+			goNext() {
+				plus.screen.unlockOrientation();
+				this.$refs.popupRef2.close();
+			},
+			showPopup(item) {
+				this.data = item;
+				this.videoId = item.jiangjie
+				//this.videoId = 'b997f16cb9cb474cb93526cff77d8801'
+				//	this.progressMarkers = item.progressMarkers
+				this.getLive(); //获取播放凭证
+				this.$refs.popupRef.open()
+			},
+			handleBack(item) {
+				this.$refs.popupRef.close()
+			},
+			getLive() {
+				let req = {
+					videoId: this.videoId
+				}
+				getVideoAuth(req).then(res => {
+					this.playAuth = res.data
+				})
+			},
+			markersClick(data) {
+				this.seekTime = ""
+				this.$nextTick(() => {
+					this.seekTime = data.offset
+				});
+			},
+		},
+		created() {
+			// console.log("getLive")
+			// this.getLive(); //获取播放凭证
+
+		},
+
+	}
+</script>
+
+
+
+<script module="renderScript" lang="renderjs">
+	export default {
+		mounted() {
+			console.log("renderScript1")
+			// 在适合的生命周期,通过script和link标签引入播放器sdk、css
+		},
+		data() {
+			return {
+				player: null,
+				playAuth: '',
+				videoId: '',
+				progressMarkers: [],
+				isFullScreen: false,
+				seekTime: '',
+				isFirst: -1,
+			}
+		},
+		methods: {
+			receiveMsg(newValue, oldValue, ownerInstance, instance) {
+				if (newValue) {
+					this.playAuth = newValue
+					this.loadWebPlayerSDK()
+				}
+			},
+			videoIdFun(newValue, oldValue, ownerInstance, instance) {
+				if (newValue) {
+					this.videoId = newValue
+				}
+			},
+			hideFlagFun(newValue, oldValue, ownerInstance, instance) {
+				if (this.player) {
+					this.player.pause()
+				}
+
+			},
+			progressMarkersMsg(newValue, oldValue, ownerInstance, instance) {
+				if (newValue) {
+					this.progressMarkers = newValue
+				}
+			},
+			seekTimeFun(newValue, oldValue, ownerInstance, instance) {
+				if (newValue) {
+					console.log(newValue, 'newValuenewValuenewValuenewValuenewValue')
+					console.log(this.player.getStatus(), 'newValuenewValuenewValuenewValuenewValue')
+					this.player.play()
+					this.player.seek(newValue)
+					//	this.player.seek(newValue)
+				}
+			},
+			playAli() {
+				if (this.isFirst == 0) {
+					this.isFirst = -1
+					return;
+				}
+				this.player = null;
+				let that = this
+				//配置播放器
+				var player = new Aliplayer({
+					id: "wgy-player-test",
+					"vid": this.videoId,
+					"playauth": this.playAuth,
+					extraInfo: {
+						poster: 'noposter'
+					},
+					fullscreenEvents: {
+						fullscreenChange: (isFull) => {
+							this.isFullScreen = isFull
+						}
+					},
+					// "playConfig": {
+					// 	"EncryptType": 'AliyunVoDEncryption'
+					// },
+					"skinLayout": [{
+							"name": "bigPlayButton",
+							"align": "blabs",
+							"x": 30,
+							"y": 80
+						},
+						{
+							"name": "controlBar",
+							"align": "blabs",
+							"x": 0,
+							"y": 0,
+							"children": [{
+									"name": "progress",
+									"align": "blabs",
+									"x": 0,
+									"y": 44
+								},
+								{
+									"name": "playButton",
+									"align": "tl",
+									"x": 15,
+									"y": 12
+								},
+								{
+									"name": "fullScreenButton",
+									"align": "tr",
+									"x": 10,
+									"y": 12
+								},
+								{
+									"name": "timeDisplay",
+									"align": "tr",
+									"x": 10,
+									"y": 5
+								}
+							]
+						}
+					],
+					"qualitySort": "asc",
+					"format": "mp4",
+					"mediaType": "video",
+					"encryptType": 1,
+					"progressMarkers": this.progressMarkers,
+					"width": '100%',
+					"height": '500px',
+					"autoplay": false,
+					"isLive": false,
+					"rePlay": false,
+					"playsinline": true,
+					"preload": false,
+					"controlBarVisibility": "hover",
+					"useH5Prism": true
+
+				}, function(player) {});
+				this.player = player;
+				player.one('canplay', function() {
+					console.log('canplay', this.player.tag);
+
+					player.tag.play();
+
+				});
+				player.on('ended', function(data) {
+					that.exitFullScreen();
+					that.$ownerInstance.callMethod('playEnd', {
+						data: 'end'
+					})
+
+				});
+				this.isFirst++;
+			},
+			exitFullScreen() {
+				if (document.exitFullscreen) {
+					document.exitFullscreen(); // 标准方法
+				} else if (document.mozCancelFullScreen) { // Firefox
+					document.mozCancelFullScreen();
+				} else if (document.webkitExitFullscreen) { // Chrome, Safari & Opera
+					document.webkitExitFullscreen();
+				} else if (document.msExitFullscreen) { // IE/Edge
+					document.msExitFullscreen();
+				}
+			},
+
+			loadWebPlayerSDK() {
+				return new Promise((resolve, reject) => {
+					const s_tag = document.createElement('script'); // 引入播放器js
+					s_tag.type = 'text/javascript';
+					s_tag.src = 'https://g.alicdn.com/de/prismplayer/2.9.6/aliplayer-min.js';
+					s_tag.charset = 'utf-8';
+					s_tag.onload = () => {
+						this.playAli()
+						resolve();
+					}
+					document.body.appendChild(s_tag);
+					const l_tag = document.createElement('link'); // 引入播放器css
+					l_tag.rel = 'stylesheet';
+					l_tag.href =
+						'https://g.alicdn.com/de/prismplayer/2.9.6/skins/default/aliplayer-min.css';
+					document.body.appendChild(l_tag);
+				});
+			},
+		}
+	}
+</script>

+ 240 - 0
pages/chanpinXuanze/components/telDialog.vue

@@ -0,0 +1,240 @@
+<template>
+	<view class="my-tel-dialog">
+		<view class="my-tel-content">
+			<view class="tel-close" @click="telClose(AWSC)"></view>
+			<view class="tel-row">
+				<view class="my-tel-title">修改手机号</view>
+				<view class="my-input-box">
+					<input class="my-input" type="text" v-model="bindObj.telNumber" placeholder="请输入手机号" maxlength="11"
+						@input="changeTelInput" />
+					<view class="close-btn" v-if="bindObj.clearTelIcon" @click="clearTel"></view>
+				</view>
+
+
+				<captcha ref="captcha" :config="config" @captchaSuccess="captchaSuccess" @captchaError="captchaError"
+					@captchaFail="captchaFail" @captchaReady="captchaReady" @captchaClose="captchaClose"></captcha>
+				<view class="get-yzm-btn" @click="getYzmBtn" :class="{ 'get-yzm-disabled': bindObj.isDisabled}">
+					{{bindObj.buttonText}}
+				</view>
+
+
+			</view>
+			<view class="yzm-row">
+				<view class="yzm-tip" v-if="bindObj.getYzmFlag">验证码已发送至:{{bindObj.telNumber}}</view>
+				<view class="my-input-box">
+					<input class="my-input" type="text" v-model="bindObj.yzmNumber" placeholder="请输入验证码" maxlength="6"
+						@input="changeYzmInput" />
+					<view class="close-btn" v-if="bindObj.clearYzmIcon" @click="clearYzm"></view>
+				</view>
+				<view @click="bindBtn" class="my-bind-btn">绑定</view>
+			</view>
+
+		</view>
+	</view>
+</template>
+<script>
+	import cacheManager from '@/utils/cacheManager.js';
+	import captcha from "@/components/captcha4/index.vue";
+	import {
+		telBind,
+		sendCode
+	} from "@/api/login.js"
+	import {
+		toast
+	} from "@/utils/common";
+	export default {
+		data() {
+			return {
+				myflag: 0,
+				sliderObj: {
+					sessionId: '',
+					sig: '',
+					token: '',
+				},
+				bindObj: {
+					telNumber: '',
+					clearTelIcon: false,
+					yzmNumber: '',
+					clearYzmIcon: false,
+					/*** 验证码 ***/
+					yzmStatus: 'login-btn-disabled',
+					timeLeft: 60, // 初始倒计时时间(秒)
+					intervalId: null, // 定时器ID
+					isDisabled: true, // 按钮是否禁用
+					buttonText: '获取验证码', // 按钮文本
+					getYzmFlag: false, // 是否发送验证码
+				},
+				config: {
+					captchaId: "9d5837b0807b8de44da0de310a0b2813",
+				},
+			}
+		},
+		components: {
+			captcha
+		},
+		methods: {
+			telClose() {
+				this.$emit('telClose')
+			},
+
+			// 清空手机号
+			clearTel() {
+				this.bindObj.telNumber = '';
+				this.bindObj.isDisabled = true;
+				this.bindObj.clearTelIcon = false;
+				this.bindObj.getYzmFlag = false;
+			},
+
+			// 判断是否输入手机号
+			changeTelInput(event) {
+				if (event.detail.value.length > 0) {
+					this.bindObj.clearTelIcon = true;
+					this.validatePhoneNumber(event.detail.value);
+				} else {
+					this.bindObj.clearTelIcon = false;
+				}
+			},
+
+			// 手机号校验规则
+			validatePhoneNumber(value) {
+				const phoneRegex = /^1[3-9]\d{9}$/;
+				if (phoneRegex.test(value)) {
+					// 通过
+					this.bindObj.isDisabled = false;
+				} else {
+					// 不通过
+					this.bindObj.isDisabled = true;
+				}
+			},
+			// 获取验证码按钮
+			getYzmBtn() {
+				// 判断手机号校验是否通过
+				if (this.bindObj.timeLeft != 60) {
+					toast('请在' + this.bindObj.timeLeft + '后重新获取验证码!')
+					return
+				} else if (this.bindObj.isDisabled === true) {
+					toast("请输入正确的手机号!")
+					return
+				} else {
+				this.$refs.captcha.showCaptcha();
+				}
+			},
+
+	captchaSuccess(result) { // app端的回调
+				console.log(result)
+				this.startCountdown();
+				this.sliderData = result;
+				this.getMessage();
+
+			},
+			captchaError(e) {
+				// app端的回调
+				toast(JSON.stringify(e))
+			},
+			captchaReady() {
+				// app端的回调
+			},
+			captchaFail() {
+				// app端的回调
+				toast('验证失败!')
+			},
+			captchaClose() {
+				// uni.redirectTo({
+				// 	url: `/pages/login/index`
+				// })
+			},
+
+
+			getMessage() {
+				let req = {
+				phone: this.bindObj.telNumber,
+				captchaOutput: this.sliderData.captcha_output,
+				genTime: this.sliderData.gen_time,
+				lotNumber: this.sliderData.lot_number,
+				passToken: this.sliderData.pass_token,
+				}
+				sendCode(req).then(res => {
+					this.bindObj.getYzmFlag = true;
+				}).catch(err => {
+					this.bindObj.getYzmFlag = false;
+					toast('验证码获取失败:' + err)
+				})
+			},
+
+			// 清空验证码
+			clearYzm() {
+				this.bindObj.yzmNumber = '';
+				this.bindObj.isDisabled = true;
+				this.bindObj.clearYzmIcon = false;
+			},
+
+			// 判断是否输入验证码
+			changeYzmInput(event) {
+				if (event.detail.value.length > 0) {
+					this.bindObj.clearYzmIcon = true;
+				} else {
+					this.bindObj.clearYzmIcon = false;
+				}
+			},
+
+			// 开始计时
+			startCountdown() {
+
+				if (this.bindObj.buttonText === '重新发送') {
+					this.sliderFlag = true;
+				}
+				this.bindObj.isDisabled = true;
+				this.bindObj.buttonText = `重新发送(${this.bindObj.timeLeft}S)`;
+
+				// 清除之前的定时器(如果有)
+				if (this.bindObj.intervalId) {
+					clearInterval(this.bindObj.intervalId);
+				}
+
+				// 设置新的定时器
+				this.bindObj.intervalId = setInterval(() => {
+					this.bindObj.timeLeft--;
+					if (this.bindObj.timeLeft <= 0) {
+						clearInterval(this.bindObj.intervalId);
+						this.bindObj.timeLeft = 60; // 重置倒计时
+						this.bindObj.isDisabled = false;
+						this.bindObj.buttonText = '重新发送';
+					} else {
+						this.bindObj.buttonText = `重新发送(${this.bindObj.timeLeft}S)`;
+					}
+				}, 1000);
+			},
+
+			// 绑定按钮
+			bindBtn() {
+				if (this.bindObj.telNumber === '') {
+					toast('手机号不能为空')
+					return;
+				}
+				if (this.bindObj.yzmNumber === '') {
+					toast('验证码不能为空')
+					return;
+				}
+
+				let req = {
+					tel: this.bindObj.telNumber,
+					code: this.bindObj.yzmNumber,
+				}
+				telBind(req).then(res => {
+					if (res.code == 0) {
+						toast('手机号绑定成功')
+						this.updataTel(this.bindObj.telNumber);
+						this.$emit('bindBtn')
+					}
+				})
+			},
+
+			// 在缓存中修改手机号
+			updataTel(data) {
+				cacheManager.updateObject('auth', {
+					userName: data
+				})
+			}
+		}
+	}
+</script>

+ 178 - 0
pages/chanpinXuanze/components/unitAnswer.vue

@@ -0,0 +1,178 @@
+<template>
+	<uni-popup ref="popupRef" :animation="false" :is-mask-click="false"
+		mask-background-color="rgba(255, 255, 255, 0.6);" class="ezy-popup-width-all">
+		<view class="ezy-result-page">
+			<view class="icon-title-navBar-box">
+				<view @click="handleBack" class="nav-bar-icon"></view>
+				<view class="nav-bar-title">成绩</view>
+			</view>
+			<view class="shiti-frame-box">
+				<w-swiper :list="myList" :positionIndex="current" class="result-exam-swiper" @change="onSwiperChange">
+					<template v-slot:default="{item,index}">
+						<view class="body" v-if="item.mta_show">
+							<danxuan :question="item" showError v-if="item.type == '1'"></danxuan>
+							<panduan :question="item" showError v-if="item.type == '2'"></panduan>
+							<tiankong :question="item" showError v-if="item.type == '3'"
+								:placeholders="item.placeholders"></tiankong>
+							<view class="answer-content-box">
+								<view class="answer-dtjx-row">
+									<view class="answer-title"></view>
+									<!-- 答案解析 -->
+									<view>答案</view>	
+								</view>
+								<view class="answer-btn-box" v-if="item.type!=3">
+									<!-- 你的答案 -->
+									<view class="answer-item-left">
+										<text class="answer-item-title">您的答案</text>
+										<text class="answer-item-error">{{showAnswerReply(item)}}</text>
+										<view class="answer-line"></view>
+									</view>
+									<!-- 答案 -->
+									<view class="answer-item-right">
+										<text class="answer-item-title">正确答案</text>
+										<text class="answer-item-correct">{{showAnswerResult(item)}}</text>
+									</view>
+								</view>
+								<view v-else>
+									<!-- 答案 -->
+									<view class="tiankong-answer-content-box">
+										<view v-for="(ict,cindex) in showAnswerResult(item)" :key="cindex"
+											class="tiankong-answer-row">
+											<text>{{cindex+1}}. </text>
+											<text v-for="(xItem,xindex) in ict" :key="xindex">
+												<text> {{xItem}} </text>
+												<text v-if="xindex != ict.length-1">/</text>
+											</text>
+										</view>
+									</view>
+								</view>
+
+							</view>
+						</view>
+					</template>
+				</w-swiper>
+			</view>
+		</view>
+		<!-- 解析浮层数据 -->
+		<questionJiexi ref="jiexiRef"></questionJiexi>
+	</uni-popup>
+</template>
+
+<script setup>
+	import questionJiexi from './questionJiexi.vue';
+	import wSwiper from '@/components/wSwiper/wSwiper.vue';
+	import danxuan from "@/components/question/danxuan.vue";
+	import panduan from "@/components/question/panduan.vue";
+	import tiankong from "@/components/question/tiankong.vue";
+	import {
+		useQuestionTools
+	} from "@/components/question/useQuestionTools.js";
+	import {
+		computed
+	} from "vue";
+	const {
+		getLetterByIndex
+	} = useQuestionTools();
+
+	import {
+		ref
+	} from "vue";
+
+	const props = defineProps({
+		list: {
+			type: Array,
+		},
+		code: {
+			type: String,
+			default: 'cj'
+		}
+	})
+
+	const myList = computed(() => {
+		return props.list.map(item => {
+			return {
+				...item,
+				code: 'cj'
+			}
+		})
+	})
+
+	const emits = defineEmits(['back'])
+
+	const current = ref(0)
+	const popupRef = ref(null)
+	const jiexiRef = ref(null);
+
+	function onSwiperChange(index) {
+		uni.$emit('swiper-change', index)
+	}
+
+	// 切换成绩
+	function showPopup() {
+		popupRef.value.open()
+	}
+
+	function closePopup() {
+		popupRef.value.close()
+	}
+
+	// 展示
+	function showJiexiPopup(data) {
+		jiexiRef.value.showPopup(data);
+	}
+
+	function handleBack() {
+		// 从 单元测试 到 岛 的路由参数
+		emits('back')
+	}
+
+	function showAnswerResult(item) {
+		if (item.type == 1) {
+			// 单选题
+			return getLetterByIndex(item.result)
+		} else if (item.type == 2) {
+			if (item.result == 1) {
+				return '正确'
+			} else {
+				return '错误'
+			}
+		} else if (item.type == 4) {
+			return getLetterByIndex(item.result)
+		} else {
+			return item.result
+		}
+	}
+
+
+	function showAnswerReply(item) {
+		if (item.type == 1) {
+			if (item.reply == null) {
+				return '未答'
+			}
+			// 单选题
+			return getLetterByIndex(item.reply)
+		} else if (item.type == 2) {
+			if (item.reply == null) {
+				return '未答'
+			}
+			if (item.reply == 1) {
+				return '正确'
+			} else {
+				return '错误'
+			}
+		} else if (item.type == 4) {
+			if (item.reply == null) {
+				return '未答'
+			}
+			// 单选题
+			return getLetterByIndex(item.reply)
+		} else {
+			return item.reply
+		}
+	}
+
+	defineExpose({
+		showPopup,
+		closePopup
+	})
+</script>

+ 77 - 0
pages/chanpinXuanze/components/unitResult.vue

@@ -0,0 +1,77 @@
+<template>
+	<uni-popup ref="popupRef" :animation="false" :is-mask-click="false"
+		mask-background-color="rgba(255, 255, 255, 0.6);" class="ezy-popup-width-all">
+		<view>
+			<!-- 导航 -->
+			<view @click="handleBack">返回</view>
+
+			<view>
+				<view>图</view>
+				<view> 单元测试已完成 </view>
+			</view>
+
+			<view>
+				<view>
+					<view>{{data.right}}</view>
+					<view>正确</view>
+				</view>
+				<view>
+					<view>{{data.wrong}}</view>
+					<view>错误</view>
+				</view>
+			</view>
+
+			<view>
+				<button @click="handleRestart">重新测试</button>
+				<button @click="handleCheckAnswer">查看答案</button>
+			</view>
+		</view>
+	</uni-popup>
+</template>
+
+<script setup>
+	import {
+		ref,
+		reactive
+	} from "vue";
+
+	const popupRef = ref(null)
+	const data = reactive({
+		right: 0,
+		wrong: 0,
+	})
+
+	const emits = defineEmits(['check-answer', 'do-replay'])
+
+	function handleRestart() {
+		emits('do-replay')
+	}
+
+	function handleCheckAnswer() {
+		emits('check-answer')
+	}
+
+	function showPopup(options) {
+		data.right = options.right;
+		data.wrong = options.wrong;
+
+		popupRef.value.open();
+	}
+
+	function closePopup() {
+		popupRef.value.close();
+	}
+
+	function handleBack() {
+		closePopup();
+	}
+
+
+	defineExpose({
+		showPopup,
+		closePopup
+	})
+</script>
+
+<style>
+</style>

+ 2 - 5
pages/chanpinXuanze/components/useShuxueUnitTest.js

@@ -12,7 +12,7 @@ import {
 } from "@/utils/common.js"
 
 
-export function useShuxueTest() {
+export function useShuxueTest(handleSeeResult, handleCheckAnswer) {
 
 
 	const data = reactive({
@@ -128,10 +128,7 @@ export function useShuxueTest() {
 			wrong: cdata.cuo,
 		})
 
-		uni.redirectTo({
-			url: `/pages/chanpinXuanze/unitTest?rigth=${cdata.dui}&wrong=${cdata.cuo}&jieId=${data.jieId}`
-		})
-
+		handleSeeResult()
 	}
 
 	onLoad((options) => {

+ 101 - 0
pages/chanpinXuanze/my.vue

@@ -0,0 +1,101 @@
+<template>
+	<view class="ezy-my-page">
+		<view class="my-head-box">
+			<icon class="head-img-box" :style="{backgroundImage: 'url(' + myInfoData.icon + ')'}"></icon>
+			<view class="head-content-box">
+				<text>{{myInfoData.nickName}}</text>
+			</view>
+		</view>
+		<!-- 图 -->
+		<!-- <img :src="" class="hyqy-box-img" /> -->
+
+		<!-- 设置 -->
+		<view class="my-list-box">
+			<view class="list-item" @click="yingyongshezhi">
+				<icon class="list-icon yysz-icon"></icon>
+				<text>应用设置</text>
+			</view>
+		</view>
+
+		<!-- 底部 -->
+		<CustomTabBar :currentTabNumber="3"></CustomTabBar>
+	</view>
+</template>
+
+<script setup>
+	import {
+		myInfo,
+		zhuxiao,
+		duihuanmaCode,
+		myCardList,
+		commonCardList
+	} from '@/api/my.js'
+	import CustomTabBar from '@/components/custom-tabbar/custom-tabbar.vue';
+	import {
+		onLoad
+	} from '@dcloudio/uni-app';
+	import {
+		reactive,
+		ref
+	} from "vue";
+
+	let myInfoData = reactive({
+		userImg: '',
+		userName: '',
+		credit: '',
+		vipFlag: '',
+		nickName: '',
+		icon: '',
+	});
+
+
+	// 获取用户数据
+	function getMyInfo() {
+		myInfo({}).then(res => {
+			myInfoData.userName = res.data.userName;
+			myInfoData.nickName = res.data.nickName;
+			if (res.data.nickName) {
+				myInfoData.nickName = res.data.nickName;
+			} else {
+				myInfoData.nickName = '鹅状元';
+			}
+			if (res.data.icon) {
+				myInfoData.icon = res.data.icon;
+			} else {
+				getUserImg(res.data.growthType)
+			}
+		})
+	}
+
+	// 获取用户头像
+	function getUserImg(data) {
+		switch (data) {
+			case 0:
+				myInfoData.icon = 'static/images/my/head-img0.png'
+				break;
+			case 1:
+				myInfoData.icon = 'static/images/my/head-img1.png'
+				break;
+			case 2:
+				myInfoData.icon = 'static/images/my/head-img2.png'
+				break;
+			case 3:
+				myInfoData.icon = 'static/images/my/head-img3.png'
+				break;
+			default:
+				myInfoData.icon = 'static/images/my/head-unlogin-img.png'
+				break;
+
+		}
+	}
+	
+	function yingyongshezhi() {
+		uni.redirectTo({
+			url: '/pages/chanpinXuanze/myInfo'
+		})
+	}
+
+	onLoad((options) => {
+		getMyInfo();
+	})
+</script>

+ 377 - 0
pages/chanpinXuanze/myInfo.vue

@@ -0,0 +1,377 @@
+<template>
+	<view class="ezy-yysz-page">
+		<view class="icon-title-navBar-box">
+			<view @click="handleBack" class="nav-bar-icon"></view>
+			<text class="nav-bar-title">应用设置</text>
+		</view>
+		<view class="ezy-tab-border">
+			<view class="yysz-row-box">
+				<view class="yysz-item img-item" @click="headClick">
+					<text>头像</text>
+					<icon class="yysz-img-box"
+						:style="{backgroundImage: 'url(' + myInfoData.icon + ')'}"></icon>
+				</view>
+				<view class="yysz-item" @click="nichengClick">
+					<text>昵称</text>
+					<text>{{myInfoData.nickName}}</text>
+				</view>
+			</view>	
+			<view class="yysz-row-box">
+				<view class="yysz-item" @click="telClick">
+					<text>手机号码</text>
+					<text>{{myInfoData.userName}}</text>
+				</view>
+			</view>
+			<view class="yysz-row-box">	
+				<view class="yysz-item" @click="aboutClick">
+					<text>关于我们</text>
+				</view>
+				<view v-if="loginFlag" class="yysz-item" @click="yinsizhengce">
+					<text>隐私政策</text>
+				</view>
+				<view class="yysz-item" @click="kefudianhua">
+					<text>客服与投诉</text>
+					<text>4001750778</text>
+				</view>
+				<view v-if="loginFlag" class="yysz-item" @click="yonghuzhuxiao">
+					<icon class="list-icon zhuxiao-icon"></icon>
+					<text>用户注销</text>
+				</view>
+				 <view class="yysz-item" @click="exitLogin">
+					<icon class="list-icon login-out-icon"></icon>
+					<text>退出登录</text>
+				</view>
+		</view>
+		</view>
+		<CustomTabBar  :currentTabNumber="3">
+		</CustomTabBar>
+		<tip-small-dialog ref="exitDialogRef" @confirm-btn="exitBtn" :content="tipContent"></tip-small-dialog>
+		<tip-small-dialog ref="zhuxiaoDialogRef" @confirm-btn="zhuxiaoBtn" :content="zhuxiaoContent"></tip-small-dialog>
+		<tel-dialog @telClose="telClose" @bindBtn="bindBtn" v-if="telDialogFlag"></tel-dialog>
+		<agree-content-dialog ref="agreeContentDialogRef" :agreeType="agreeType"></agree-content-dialog>
+		<tip-small-dialog ref="kefuDialogRef" :title="kefuTitle" @confirm-btn="kefuBtn" :content="kefuContent"
+			class="kefu-dialog"></tip-small-dialog>
+		<nichengDialog ref="nichengDialogRef" @confirm-btn="nichengBtn" title="修改昵称"></nichengDialog>
+	</view>
+</template>
+
+<script setup>
+	import agreeContentDialog from '@/pages/login/agreeContentDialog.vue';
+	import {
+		toast,
+	} from "@/utils/common";
+	import cacheManager from '@/utils/cacheManager.js';
+	import {
+		logout
+	} from '@/api/login.js'
+	import {
+		myInfo,
+		zhuxiao,
+		duihuanmaCode,
+		nichengUpdate,
+		myCardList,
+		commonCardList,
+		getFilePolicy,
+		updataHead
+	} from '@/api/my.js'
+	import CustomTabBar from '@/components/custom-tabbar/custom-tabbar.vue';
+	import {
+		onLoad,onShow
+	} from '@dcloudio/uni-app';
+	import {
+		reactive,
+		ref
+	} from "vue";
+	import tipSmallDialog from '@/components/dialog/tipSmallDialog.vue';
+	import duihuanmaDialog from '@/components/dialog/duihuanmaDialog.vue';
+	import nichengDialog from '@/components/dialog/nichengDialog.vue';
+	import tipMiddleDialog from '@/components/dialog/tipMiddleDialog.vue';
+	import tipBigDialog from '@/components/dialog/tipBigDialog.vue';
+	import telDialog from './components/telDialog.vue'
+	
+	import { usePermission } from "@/store/permissionStore.js"
+	const permissionStore = usePermission()
+	
+	const agreeType = ref(null);
+	const agreeContentDialogRef = ref(null);
+
+	const tipContent = '你确定要执行这个操作吗?';
+	const zhuxiaoContent = '你确定要执行这个操作吗?';
+	let loginFlag = ref(false);
+	let telDialogFlag = ref(false);
+	let myInfoData = reactive({
+		userImg: '',
+		userName: '',
+		credit: '',
+		vipFlag: '',
+		nickName: '',
+		icon: '',
+	});
+	let routerOpt = ref(false);
+	let appleCode = ref(null);
+	let currentPlatform = ref(null);
+	const exitDialogRef = ref(null);
+	const zhuxiaoDialogRef = ref(null);
+	const nichengDialogRef = ref(null);
+
+	const kefuDialogRef = ref(null);
+	const kefuTitle = '提示';
+	const kefuContent = '客服电话:4001750778';
+	const exitLogin = () => {
+		exitDialogRef.value.handleShow();
+	}
+
+	function handleBack() {
+		uni.redirectTo({
+			url: '/pages/chanpinXuanze/my'
+		})
+	}
+
+	function headClick() {
+		chooseImage()
+	}
+
+	const checkAlbumPermission = async () => {
+		const status = await uni.getSetting()
+		if (!status.authSetting['scope.album']) {
+			await uni.authorize({
+				scope: 'scope.album'
+			})
+		}
+	}
+	const chooseImage = async () => {
+		try {
+		//	await checkAlbumPermission()
+			/* #ifdef APP */
+			const systemInfo = uni.getSystemInfoSync();
+			if (systemInfo.platform != 'ios') {
+				if (!await permissionStore.requstPermission('READ_EXTERNAL_STORAGE')) return
+			}
+			/* #endif */
+		
+			uni.chooseImage({
+				count: 1,
+				sizeType: ['compressed'],
+				sourceType: ['album'], // 仅限相册选择‌:ml-citation{ref="1" data="citationList"}
+				success: (res) => {
+
+					uploadFile(res.tempFilePaths[0])
+				},
+				fail: (err) => {
+					console.error('选择失败:', err)
+				}
+			})
+		} catch (err) {
+			uni.showModal({
+				title: '权限申请失败',
+				content: '请前往设置开启相册权限'
+			})
+		}
+	}
+
+	function updateIcon(data) {
+		updataHead({
+			icon: data
+		}).then(res => {
+			if (res.code == 0) {
+				uni.showToast({
+					title: '上传成功',
+					icon: 'success'
+				});
+			} else {
+				uni.showToast({
+					title: '上传失败',
+				});
+			}
+		})
+	}
+
+	function uploadFile(filePath) {
+		const suffix = filePath.split('.').pop();
+		let req = {
+			prefix: 'resource/',
+			suffix: suffix
+		}
+		getFilePolicy(req).then(res => {
+			if (res.code === 0) {
+				const policyData = res.data;
+				console.log('policyData', policyData);
+				uni.uploadFile({
+					url: policyData.uploadUrl,
+					filePath: filePath,
+					name: 'file',
+					formData: {
+						key: policyData.key,
+						policy: policyData.policy,
+						OSSAccessKeyId: policyData.accessid,
+						signature: policyData.signature,
+						success_action_status: '200'
+					},
+					header: {
+						'Content-Type': 'multipart/form-data'
+					},
+					success(uploadRes) {
+						console.log('uploadRes', uploadRes);
+						if (uploadRes.statusCode === 200) {
+							myInfoData.icon = `${policyData.downloadUrl}/${policyData.key}`;
+							updateIcon(myInfoData.icon)
+						} else {
+							uni.showToast({
+								title: '阿里云上传错误,请重试!',
+							});
+							return false
+						}
+					},
+					fail(err) {
+						console.log('err', err);
+					}
+				});
+
+
+			}
+		})
+
+	}
+
+	function nichengClick() {
+		nichengDialogRef.value.handleShow();
+	}
+	// 退出按钮
+	const exitBtn = () => {
+		if (loginFlag.value) {
+			logout().then(res => {
+				toast('退出登录成功')
+				cacheManager.clearAll();
+				uni.reLaunch({
+					url: '/pages/login/index'
+				});
+			}).catch(err => {
+				toast('退出登录失败,请稍后重试')
+			})
+		} else {
+			uni.reLaunch({
+				url: '/pages/login/index'
+			});
+		}
+
+	}
+	const zhuxiaoBtn = () => {
+		let req = {
+
+		}
+		zhuxiao().then(res => {
+			cacheManager.clearAll();
+			toast('用户注销成功')
+			uni.redirectTo({
+				url: '/pages/login/index'
+			});
+		}).catch(err => {
+			toast('失败,请稍后重试')
+		})
+	}
+
+	function yonghuzhuxiao() {
+		zhuxiaoDialogRef.value.handleShow();
+	}
+
+	function nichengBtn(data) {
+		console.log('data', data);
+		let req = {
+			nickName: data
+		}
+		nichengUpdate(req).then(res => {
+			if (res.code == 0) {
+				toast('修改成功')
+				myInfoData.nickName = data
+			} else {
+				toast('修改失败请重试或联系管理员')
+				return false
+			}
+		}).catch(err => {
+
+		})
+	}
+
+	function yinsizhengce() {
+		agreeType.value = 'ystk'
+		agreeContentDialogRef.value.handleShow();
+	}
+
+	function kefudianhua() {
+		kefuDialogRef.value.handleShow();
+	}
+
+	function kefuBtn() {
+		kefuDialogRef.value.handleClose();
+	}
+	// 手机号码
+	function telClick() {
+		if (loginFlag.value) {
+			telDialogFlag.value = true;
+		} else {
+			youkeDialogRef.value.handleShow();
+		}
+
+	}
+	// 手机号码绑定
+	function bindBtn() {
+		telDialogFlag.value = false;
+		myGetAuth()
+	}
+	// 关闭手机号码弹窗
+	function telClose() {
+		telDialogFlag.value = false;
+	}
+	// 关于我们
+	function aboutClick() {
+		uni.redirectTo({
+			url: '/pages/chanpinXuanze/aboutPage'
+		});
+	}
+	// 获取用户数据
+	function getMyInfo() {
+		myInfo({}).then(res => {
+			myInfoData.userName = res.data.userName;
+			myInfoData.credit = res.data.credit;
+			myInfoData.nickName = res.data.nickName;
+
+			if (res.data.nickName) {
+				myInfoData.nickName = res.data.nickName;
+			} else {
+				myInfoData.nickName = '鹅状元';
+			}
+			if (res.data.icon) {
+				myInfoData.icon = res.data.icon;
+			} else {
+				getUserImg(res.data.growthType)
+			}
+
+		})
+	}
+
+	function getUserImg(data) {
+		switch (data) {
+			case 0:
+				myInfoData.icon = 'static/images/my/head-img0.png'
+				break;
+			case 1:
+				myInfoData.icon = 'static/images/my/head-img1.png'
+				break;
+			case 2:
+				myInfoData.icon = 'static/images/my/head-img2.png'
+				break;
+			case 3:
+				myInfoData.icon = 'static/images/my/head-img3.png'
+				break;
+			default:
+				myInfoData.icon = 'static/images/my/head-unlogin-img.png'
+				break;
+
+		}
+	}
+
+	onLoad((options) => {
+		loginFlag.value = true;
+		getMyInfo();
+	})
+</script>

+ 43 - 9
pages/chanpinXuanze/unitTest.vue

@@ -1,5 +1,6 @@
 <template>
 	<view class="ezy-exam-page">
+
 		<view class="icon-title-navBar-box">
 			<view @click="handleBack" class="nav-bar-icon"></view>
 			<text class="nav-bar-title">单元测试</text>
@@ -16,20 +17,19 @@
 		<view class="shiti-frame-box">
 			<w-swiper :list="data.list" :current="data.current" class="ezy-exam-swiper" @change="onSwiperChange">
 				<template v-slot:default="{item}">
-					<view>
-						<text v-if="item.type == '1'">单选题</text>
-						<text v-if="item.type == '2'">判断题</text>
-						<text v-if="item.type == '3'">填空题</text>
-					</view>
 					<view class="body" v-if="item.mta_show">
 						<danxuan :question="item" v-if="item.type == '1'"></danxuan>
 						<panduan :question="item" v-if="item.type == '2'"></panduan>
 						<tiankong :question="item" v-if="item.type == '3'" :placeholders="item.placeholders"></tiankong>
+						<button type="primary" v-if="item.stId == data.list[data.total-1].stId"
+							@click="handleSubmit">交卷</button>
 					</view>
 				</template>
 			</w-swiper>
 		</view>
 
+
+
 		<!--  左右滑动提示  -->
 		<view>
 			<view>
@@ -39,6 +39,10 @@
 
 		<!-- 填空 -->
 		<FillItem :value="result" ref="popupRef" @blur="onBlur"></FillItem>
+
+		<unitResultVue ref="uniResRef" @check-answer="onCheckAnswer" @do-replay="onDoReplay"></unitResultVue>
+
+		<unitAnswerVue :list="data.list" ref="uniAnsRef" @back="handleBack"></unitAnswerVue>
 	</view>
 </template>
 
@@ -49,6 +53,8 @@
 	import danxuan from "@/components/question/danxuan.vue";
 	import panduan from "@/components/question/panduan.vue";
 	import tiankong from "@/components/question/tiankong.vue";
+	import unitResultVue from './components/unitResult.vue';
+	import unitAnswerVue from "./components/unitAnswer.vue";
 
 	import * as httpApi from "@/api/chanpinShuxue.js"
 	import {
@@ -62,12 +68,38 @@
 		useShuxueTest
 	} from "./components/useShuxueUnitTest.js"
 	const {
-		data
-	} = useShuxueTest()
+		data,
+		handleSubmit
+	} = useShuxueTest(handleSeeResult, handleCheckAnswer)
 
 	const curTiankong = ref(null);
 	const result = ref('');
 	const popupRef = ref(null);
+	const uniResRef = ref(null);
+	const uniAnsRef = ref(null);
+
+
+	function handleSeeResult() {
+		uniResRef.value.showPopup({
+			right: data.right,
+			wrong: data.wrong
+		})
+	}
+
+	function handleCheckAnswer() {
+		uniResRef.value.showPopup({
+			jieId: data.jieId
+		})
+	}
+
+	function onDoReplay() {
+
+	}
+
+	function onCheckAnswer() {
+		uniAnsRef.value.showPopup();
+	}
+
 
 	onLoad(() => {
 		uni.$on('tiankong-fillItem', (val) => {
@@ -100,10 +132,12 @@
 		dom && dom.handleClear();
 	}
 
-	function handleBack() {}
+	function handleBack() {
+		uni.navigateBack()
+	}
 
 	function onSwiperChange(index) {
-		current.value = index;
+		data.current = index;
 		uni.$emit('swiper-change', index)
 	}
 </script>