Bläddra i källkod

Merge branch 'main' of https://gogs.mtavip.com/wangguoyu/uniProject into main

tanxue 1 månad sedan
förälder
incheckning
7b77f3ddec

+ 24 - 0
api/course.js

@@ -10,3 +10,27 @@ export function getKechengList(data = {}) {
     timeout: 20000
   })
 }
+
+export function kechengStart(data = {}) {
+  return request({
+    'url': '/app/kecheng/start',
+    headers: {
+      isToken: true
+    },
+    method: 'post',
+    data,
+    timeout: 20000
+  })
+}
+
+export function kejianInfo(data = {}) {
+  return request({
+    'url': '/app/kejian/info',
+    headers: {
+      isToken: true
+    },
+    method: 'post',
+    data,
+    timeout: 20000
+  })
+}

+ 1 - 1
api/exam.js

@@ -118,7 +118,7 @@ export function getClientKsSubmit(data = {}) {
     timeout: 20000
   })
 }
-
+// 不存在
 export function getClientUserInfo(data = {}) {
   return request({
     url: '/app/kaoshi/user/info',

+ 73 - 0
components/kaoshixuzhi/kaoshixuzhi.vue

@@ -0,0 +1,73 @@
+<template>
+	<view>
+		<uni-popup ref="popupRef" type="dialog" :animation="false" :is-mask-click="false"
+		mask-background-color="rgba(0, 0, 0, 0.4);">
+			<uni-popup-dialog mode="input"
+			class="phone-ksxz-dialog"
+				title="考试须知"
+				:duration="2000" 
+				:before-close="true"
+				@close="handleClose"
+				@confirm="handleConfirm">
+				<view class="ksxz-content-box">
+					<view v-if="data.ksName">考试名称:{{data.ksName}}</view>
+					<view v-if="data.zyName">职业:{{data.zyName}}</view>
+					<view v-if="data.zyLevelName">等级:{{data.zyLevelName}}</view>
+					<view v-if="data.ksScore">总分:{{data.ksScore}}</view>
+					<view v-if="data.okScore">及格分:{{data.okScore}}</view>
+					<view>
+						<view v-if="data.intro" class="ksms-row">考试描述:</view>
+						<rich-text v-if="data.intro" :nodes="data.intro" class="ksms-intro"></rich-text>
+					</view>
+				</view>
+			</uni-popup-dialog>
+		</uni-popup>
+	</view>
+</template>
+
+<script setup>
+	import {
+		ref,reactive
+	} from "vue";
+	const popupRef = ref(null)
+	const data = reactive({
+		intro: '',
+		ksName: '',
+		ksScore: '',
+		okScore: '',
+		zyLevelName: '',
+		zyName: '',
+	})
+	
+	const emits = defineEmits(['confirm', 'cancel'])
+
+	function showDialog(options) {
+		data.intro = options.intro;
+		data.ksName = options.ksName;
+		data.ksScore = options.ksScore;
+		data.okScore = options.okScore;
+		data.zyName = options.zyName;
+		data.zyLevelName = options.zyLevelName;
+		data.ksId = options.ksId;
+		
+		popupRef.value.open()
+	}
+
+	function handleClose() {
+		emits('cancel');
+		popupRef.value.close()
+	}
+
+	function handleConfirm() {
+		emits('confirm', data);
+		popupRef.value.close()
+	}
+
+	defineExpose({
+		showDialog
+	})
+</script>
+
+<style lang="scss">
+
+</style>

+ 73 - 0
components/kaoshixuzhi/lianxixuzhi.vue

@@ -0,0 +1,73 @@
+<template>
+
+	<uni-popup ref="popupRef" type="dialog" :animation="false" :is-mask-click="false"
+	mask-background-color="rgba(0, 0, 0, 0.4);">
+		<uni-popup-dialog mode="input"
+		class="phone-ksxz-dialog"
+			title="练习须知"
+			:duration="2000" 
+			:before-close="true"
+			@close="handleClose"
+			@confirm="handleConfirm">
+			<view class="ksxz-content-box">
+				<view v-if="data.lxName">练习名称:{{data.lxName}}</view>
+				<view v-if="data.zyName">职业:{{data.zyName}}</view>
+				<view v-if="data.zyLevelName">等级:{{data.zyLevelName}}</view>
+				<view v-if="data.ksScore">总分:{{data.ksScore}}</view>
+				<view v-if="data.okScore">及格分:{{data.okScore}}</view>
+				<view>
+					<view v-if="data.intro" class="ksms-row">练习描述:</view>
+					<rich-text v-if="data.intro" :nodes="data.intro" class="ksms-intro"></rich-text>
+				</view>
+			</view>
+		</uni-popup-dialog>
+	</uni-popup>
+
+</template>
+
+<script setup>
+	import {
+		ref,reactive
+	} from "vue";
+	const popupRef = ref(null)
+	const data = reactive({
+		intro: '',
+		lxName: '',
+		ksScore: '',
+		okScore: '',
+		zyLevelName: '',
+		zyName: '',
+	})
+	
+	const emits = defineEmits(['confirm', 'cancel'])
+
+	function showDialog(options) {
+		data.intro = options.intro;
+		data.lxName = options.lxName;
+		data.ksScore = options.ksScore;
+		data.okScore = options.okScore;
+		data.zyName = options.zyName;
+		data.zyLevelName = options.zyLevelName;
+		data.lxId = options.lxId;
+		
+		popupRef.value.open()
+	}
+
+	function handleClose() {
+		emits('cancel');
+		popupRef.value.close()
+	}
+
+	function handleConfirm() {
+		emits('confirm', data);
+		popupRef.value.close()
+	}
+
+	defineExpose({
+		showDialog
+	})
+</script>
+
+<style lang="scss">
+
+</style>

+ 25 - 0
components/questions/jianda.vue

@@ -0,0 +1,25 @@
+<template>
+	<view v-if="question" class="phone-jianda-box">
+		<view class="phone-shiti-question">
+			<view class="question-num">{{question.onlyNum}}、</view>
+			<!-- 题干区域 -->
+			<rich-text :nodes="question.name"></rich-text>
+		</view>
+		<!-- 选项区域 -->
+		<view  class="jianda-option-box">
+			<textarea placeholder="请输入内容" v-model="question.reply" />
+		</view>
+	</view>
+</template>
+
+<script setup>
+	const props = defineProps({
+		question: {
+			type: Object,
+		},
+		showError: {
+			type: Boolean,
+			default: false
+		}
+	})
+</script>

+ 89 - 0
components/questions/yuedu.vue

@@ -0,0 +1,89 @@
+<template>
+	<view v-if="question" class="phone-yuedu-box">
+		<view class="phone-shiti-question">
+			<view class="question-num">{{question.onlyNum}}、</view>
+			<!-- 题干区域 -->
+			<!-- <rich-text :nodes="question.name"></rich-text> -->
+		</view>
+		<!-- 选项区域 -->
+		<view class="yuedu-option-box">
+			<swiper class="swiper-box" @change="onSwitchChange" :current="swiperDotIndex">
+				<swiper-item v-for="(item,index) in data.content" :key="index">
+												{{item}}
+					<view class="swiper-item" :class="'swiper-item' + index" style="height: 300rpx;background-color: #ccc;">
+						<template v-if="item.stTypeId == 1">
+							<!-- 单选 -->
+							<danxuan :question="item" :key="item.stId"></danxuan>
+						</template>
+						<template v-if="item.stTypeId == 2">
+
+							<!-- 多选 -->
+							<duoxuan :question="item" :key="item.stId"></duoxuan>
+						</template>
+						<template v-if="item.stTypeId == 3">
+							<!-- 判断 -->
+							<panduan :question="item" :key="item.stId"></panduan>
+						</template>
+						<template v-if="item.stTypeId == 4">
+							<!-- 填空 -->
+							<tiankong :question="item" :key="item.stId"></tiankong>
+						</template>
+						<template v-if="item.stTypeId == 5">
+							<!-- 简答 -->
+							<jianda :question="item" :key="item.stId"></jianda>
+						</template>
+					</view>
+				</swiper-item>
+			</swiper>
+		</view>
+	</view>
+</template>
+
+<script setup>
+	import {
+		reactive,
+		watch,
+		ref
+	} from 'vue';
+	import danxuan from "@/components/questions/danxuan.vue";
+	import duoxuan from "@/components/questions/duoxuan.vue";
+	import tiankong from "@/components/questions/tiankong.vue";
+	import panduan from "@/components/questions/panduan.vue";
+	import jianda from "@/components/questions/jianda.vue";
+	const props = defineProps({
+		question: {
+			type: Object,
+		},
+		showError: {
+			type: Boolean,
+			default: false
+		}
+	})
+	const data = reactive({
+		content: []
+	})
+
+	const swiperDotIndex = ref(0);
+
+	watch(() => props.question, (question) => {
+		data.content = [...question.danxuan, ...question.duoxuan, ...question.panduan, ...question.tiankong, ...
+			question.jianda
+		];
+		data.content.map((item,index) => {
+			item.onlyNum = index+1;
+			return item
+		})
+	}, {
+		immediate: true
+	})
+
+	function onSwitchChange(e) {
+		console.log('eeee', e)
+	}
+</script>
+
+<style lang="scss">
+	.swiper-item {
+		height: 200px;
+	}
+</style>

+ 1 - 1
components/scroll-list-card/scroll-list-card.vue

@@ -26,7 +26,7 @@
     <template v-for="item in btns" :key="item.status">
       <button
         class="lli-btn"
-        @click="btnClick(item)"
+        @click="btnClick(data)"
         v-if="item.show"
         :key="item.status"
         :disabled="data.disabled"

+ 210 - 10
pages/course/kechengInfo.vue

@@ -1,27 +1,227 @@
 <template>
-		<view>asdfsdfas</view>
+	<view class="course-container">
+		<!-- 视频播放器 -->
+		<video v-if="currentVideo.url" :src="currentVideo.url" :id="videoId" controls @ended="handleVideoEnd"
+			@timeupdate="handleTimeUpdate" @loadedmetadata="handleVideoLoaded">
+		</video>
+
+		<!-- 课程信息 -->
+		<view class="course-header">
+			<text class="course-title">测试课程1</text>
+			<view class="course-meta">
+				<text>讲师:张老师</text>
+				<text>时长:3分42秒</text>
+				<text>1人学习</text>
+			</view>
+		</view>
+
+		<!-- 选项卡 -->
+		<view class="course-tabs">
+			<text :class="['tab-item', activeTab === '目录' ? 'active' : '']" @click="activeTab = '目录'">目录</text>
+			<text :class="['tab-item', activeTab === '介绍' ? 'active' : '']" @click="activeTab = '介绍'">介绍</text>
+			<text :class="['tab-item', activeTab === '评论' ? 'active' : '']" @click="activeTab = '评论'">评论</text>
+			<text :class="['tab-item', activeTab === '考试' ? 'active' : '']" @click="activeTab = '考试'">考试</text>
+		</view>
+
+		<!-- 目录内容 -->
+		<view v-if="activeTab === '目录'" class="course-content">
+			<catalogue ref="catalogueRef" @kejianInfo='getKejianInfo' :options="kejianUserVo" 
+				:current-video="currentVideo"></catalogue>
+
+		</view>
+
+	</view>
 </template>
 
 <script setup>
 	import {
-		getKechengList
-	} from "@/api/course.js";
+		ref,
+		onMounted
+	} from 'vue';
 	import {
 		onLoad,
-		onReady
+		onReady,
+
 	} from "@dcloudio/uni-app"
 	import {
-		reactive,
-		ref
-	} from "vue";
+		kechengStart
+	} from "@/api/course.js";
+	import catalogue from './common/catalogue.vue';
+	// 选项卡状态
+	const activeTab = ref('');
+	let kcId = ref('');
+	let kejianUserVo = ref(null);
+	// 当前播放信息
+	const currentVideo = ref({
+		url: '',
+		kjId: ''
+	});
+	const currentChapter = ref(0);
+	const currentSection = ref(0);
+	const catalogueRef = ref(null);
+	const videoId = ref('courseVideo');
+	let videoContext = null;
 	onLoad((options) => {
-		console.log('options',options);
+		console.log('options', options);
+		kcId.value = options.kcId
+		getKechengData()
+	});
+	onMounted(() => {
+
 	});
-	const kechengClick = ()=>{
+
+	function getKechengData() {
+		kechengStart({
+			kcId: kcId.value
+		}).then(res => {
+			console.log('res', res);
+			kejianUserVo.value = res.data.kejianUserVo
+			activeTab.value = '目录'
+		})
+	}
+
+	function getKejianInfo(data) {
+		console.log('data', data);
+		// currentVideo.value = {
+		// 	url: data.url || 'https://www.w3school.com.cn/example/html5/mov_bbb.mp4',
+		// 	kjId: data.kjId
+		// };	
+		currentVideo.value = {
+			url: 'https://www.w3school.com.cn/example/html5/mov_bbb.mp4',
+			kjId: data.kjId
+		};
 		
+		setTimeout(() => {
+			if (!videoContext) {
+				videoContext = uni.createVideoContext(videoId.value, this);
+			}
+			const cachedTime = uni.getStorageSync(`video_${data.kjId}`) || 0;
+			videoContext.seek(cachedTime);
+		}, 300);
 	}
+
+
+	const handleTimeUpdate = (e) => {
+		const currentTime = e.detail.currentTime;
+		uni.setStorageSync(`video_${currentVideo.value.kjId}`, currentTime);
+	};
+
+	const handleVideoEnd = () => {
+		catalogueRef.value.playNextVideo();
+	};
+
+	const handleVideoLoaded = (e) => {
+		uni.setStorageSync(`duration_${currentVideo.value.kjId}`, e.detail.duration);
+	};
 </script>
 
-<style lang="scss">
+<style scoped>
+	.course-container {
+		display: flex;
+		flex-direction: column;
+		height: 100vh;
+	}
+
+	.course-header {
+		padding: 20rpx;
+		background: #f5f5f5;
+	}
+
+	.course-title {
+		font-size: 36rpx;
+		font-weight: bold;
+	}
+
+	.course-meta {
+		margin-top: 10rpx;
+		font-size: 24rpx;
+		color: #666;
+	}
+
+	.course-tabs {
+		display: flex;
+		justify-content: space-around;
+		padding: 20rpx;
+		background: #fff;
+		border-bottom: 1rpx solid #ddd;
+	}
+
+	.tab-item {
+		font-size: 28rpx;
+		color: #666;
+	}
+
+	.tab-item.active {
+		color: #09BB07;
+		font-weight: bold;
+	}
+
+	.course-content {
+		flex: 1;
+		overflow-y: auto;
+		padding: 20rpx;
+	}
+
+	.chapter-list {
+		background: #fff;
+	}
+
+	.chapter-item {
+		margin-bottom: 20rpx;
+	}
+
+	.chapter-title {
+		padding: 20rpx;
+		background: #f5f5f5;
+		display: flex;
+		justify-content: space-between;
+		border-bottom: 1rpx solid #ddd;
+	}
+
+	.section-list {
+		background: #fff;
+	}
+
+	.section-item {
+		padding: 20rpx;
+		display: flex;
+		justify-content: space-between;
+		border-bottom: 1rpx solid #eee;
+	}
+
+	.section-info {
+		flex: 1;
+	}
+
+	.section-title {
+		display: block;
+		font-size: 28rpx;
+		color: #333;
+	}
+
+	.play-status {
+		width: 180rpx;
+		text-align: right;
+	}
 
+	.playing {
+		color: #09BB07;
+		font-size: 24rpx;
+	}
+
+	.progress {
+		color: #666;
+		font-size: 24rpx;
+	}
+
+	.unplayed {
+		color: #999;
+		font-size: 24rpx;
+	}
+
+	video {
+		width: 100%;
+		height: 300rpx;
+		background: #000;
+	}
 </style>

+ 217 - 58
pages/exam/exam.vue

@@ -10,12 +10,10 @@
 			<view v-if="activeSt" class="title-types">{{dlName}}</view>
 			<!--  倒计时 -->
 			<view v-if="!!data.endSecond">
-				<uni-countdown :show-day="false" :showHour="true" :showMinute="true" :second="data.endSecond" @timeup="onTimeUp"
-					:start="startCountDown"></uni-countdown>
+				<uni-countdown :show-day="false" :showHour="true" :showMinute="true" :second="data.endSecond"
+					@timeup="onTimeUp" :start="startCountDown"></uni-countdown>
 			</view>
 		</view>
-
-
 		<view class="kaoshi-shiti-content">
 			<!-- 内容区域 -->
 			<!-- 试题区域 -->
@@ -36,6 +34,14 @@
 					<!-- 填空 -->
 					<tiankong :question="activeSt" :key="activeSt.stId"></tiankong>
 				</template>
+				<template v-if="activeSt.stTypeId == 5">
+					<!-- 简答 -->
+					<jianda :question="activeSt" :key="activeSt.stId"></jianda>
+				</template>
+				<template v-if="activeSt.stTypeId == 6">
+					<!-- 阅读 -->
+					<yuedu :question="activeSt" :key="activeSt.stId"></yuedu>
+				</template>
 			</view>
 
 		</view>
@@ -81,21 +87,21 @@
 			</view>
 		</uni-popup>
 		<!-- 摄像头确认 -->
-	<!-- 	<zhuapaiConfirm ref="zhuapaiConfirmRef" @success="zpConfirmSuccess" @error="zpConfirmError" 
+		<!-- 	<zhuapaiConfirm ref="zhuapaiConfirmRef" @success="zpConfirmSuccess" @error="zpConfirmError" 
 			@cancel="zpConfirmCancel" key="1"></zhuapaiConfirm> -->
 		<template v-if="data.zhuapai && data.zhuapai > 0">
 			<!-- 抓拍 -->
 			<!-- <zhuapaiVue ref="zhuapaiRef" @error="zpError" @success="zpSuccess" key="2" @progress="onProgress"></zhuapaiVue> -->
 		</template>
-	
+
 		<!-- 切屏 -->
-	<!-- 	<qiepingVue ref="qiepingRef" @zhuapai="qpZhuapai" @forceSubmit="forceSubmit" @qiepingToast="qiepingToast"
+		<!-- 	<qiepingVue ref="qiepingRef" @zhuapai="qpZhuapai" @forceSubmit="forceSubmit" @qiepingToast="qiepingToast"
 			key="3"></qiepingVue> -->
 		<!-- 交卷确认 -->
 		<answerQueren ref="answerQrRef" @confirm="handleQuerenConfirm"></answerQueren>
 		<!-- 考试得分 -->
 		<submitScoreVue ref="subScoreRef" @confirm="handleScoreConfirm" @close="handleScoreClose"></submitScoreVue>
-		
+
 		<!-- 切屏确认弹窗 -->
 		<!-- <qiepingDlVue ref="qiepingDlRef" :content="messageContent" title="注意" okBtn="知道了"></qiepingDlVue> -->
 	</view>
@@ -122,6 +128,8 @@
 	import duoxuan from "@/components/questions/duoxuan.vue";
 	import tiankong from "@/components/questions/tiankong.vue";
 	import panduan from "@/components/questions/panduan.vue";
+	import jianda from "@/components/questions/jianda.vue";
+	import yuedu from "@/components/questions/yuedu.vue";
 	import {
 		useQuestionTools
 	} from "@/components/questions/useQuestionTools.js";
@@ -146,14 +154,13 @@
 	onLoad((option) => {
 		data.ksId = option.ksId;
 		data.zhuapai = option.zhuapai;
-		data.userKaozhengId = option.userKaozhengId;
-		data.from = option.from;
 		if (data.zhuapai && data.zhuapai != 0) {
 			// 考试前确认摄像头
 			nextTick(() => {
-				initBeforKaoshi();
+				// initBeforKaoshi();
 			})
 		} else {
+			console.log('初始化')
 			initKaoshi();
 		}
 	})
@@ -168,7 +175,7 @@
 	const subScoreRef = ref(null);
 	const messageContent = ref('');
 	const qiepingDlRef = ref(null);
-	
+
 	const timer1 = ref(null);
 
 	const data = reactive({
@@ -187,9 +194,8 @@
 		StListForSearch: [],
 		from: '',
 		hisId: '',
-		userKaozhengId: ''
 	})
-	
+
 	const markDB = ref([]);
 
 	const questionData = ref([]);
@@ -235,21 +241,21 @@
 			return false
 		}
 	});
-	
+
 
 	function handleScoreClose() {
 		handleBack()
 	}
-	
+
 	// 考试得分相关 start
 	function handleScoreConfirm() {
 		uni.redirectTo({
 			url: `/pages/client/Chengji/ksScoreShijuan?hisId=${data.hisId}&from=kaoshi`
 		})
 	}
-	
+
 	// 考试得分相关 end
-	
+
 	// 保存相关
 	function handleSave(showToast) {
 		if (timer1.value) {
@@ -257,13 +263,13 @@
 				title: '请勿连续保存',
 				icon: 'none'
 			})
-			return 
+			return
 		}
 		timer1.value = setTimeout(() => {
 			clearTimeout(timer1.value);
-		},10*1000);
+		}, 10 * 1000);
 		console.log(questionData.value)
-		
+
 		const result = []
 		const option = {
 			force: false,
@@ -281,7 +287,13 @@
 			})
 		})
 		// 保存试题答案
-		saveCacheKs(data.operId, {replyList:result, position: {dlIndex:progress.dlIndex, dtIndex: progress.dtIndex}})
+		saveCacheKs(data.operId, {
+			replyList: result,
+			position: {
+				dlIndex: progress.dlIndex,
+				dtIndex: progress.dtIndex
+			}
+		})
 		// 保存答题进度
 		ksApi.getClientKsSave(option).then(res => {
 			if (res.data && showToast) {
@@ -347,7 +359,7 @@
 	function handleQuerenConfirm() {
 		handleSubmit()
 	}
-	
+
 	function handleSubmit(force = false) {
 		const result = {
 			force,
@@ -363,7 +375,7 @@
 				result.replyList.push(opt)
 			})
 		})
-	
+
 		ksApi.getClientKsSubmit(result).then(res => {
 			if (res.code == 0) {
 				subScoreRef.value.showDialog(res.data);
@@ -373,7 +385,7 @@
 			}
 		})
 	}
-	
+
 	function onTimeUp() {
 		handleSubmit();
 	}
@@ -420,7 +432,9 @@
 		})
 		handleBack();
 	}
+
 	function zpConfirmSuccess() {
+		console.log('zpConfirmSuccess')
 		initKaoshi();
 	}
 
@@ -474,19 +488,20 @@
 
 	function answerCardItemClick(qa) {
 		const actQa = data.StListForSearch.find(item => item.stId == qa.stId);
+		console.log('actQa', actQa)
 		skipQuestion(actQa.dlIndex, actQa.dtIndex)
 
 	}
 
 	function handleBack() {
-		 const pages = getCurrentPages();
-		 if (pages.length>1) {
-			 uni.navigateBack()
-		 } else {
-			  history.back();
-		 }
-		
-		
+		const pages = getCurrentPages();
+		if (pages.length > 1) {
+			uni.navigateBack()
+		} else {
+			history.back();
+		}
+
+
 	}
 
 	function showAnswerCard() {
@@ -532,7 +547,7 @@
 			let order = 0; // 当前题型中第几题
 			for (const iDanxuan of duanluo.danxuan) {
 				iDanxuan.type = 'danxuan';
-				iDanxuan.marked = data.biaoji[iDanxuan.stId] ? true: false;
+				iDanxuan.marked = data.biaoji[iDanxuan.stId] ? true : false;
 				iDanxuan.onlyNum = uIndex + 1;
 				iDanxuan.order = order;
 				iDanxuan.iQa = iQa;
@@ -552,7 +567,7 @@
 			order = 0;
 			for (const iDuoxuan of duanluo.duoxuan) {
 				iDuoxuan.type = 'duoxuan';
-				iDuoxuan.marked = data.biaoji[iDuoxuan.stId] ? true: false;
+				iDuoxuan.marked = data.biaoji[iDuoxuan.stId] ? true : false;
 				iDuoxuan.onlyNum = uIndex + 1;
 				iDuoxuan.order = order;
 				paragraph.qas.push(iDuoxuan);
@@ -573,7 +588,7 @@
 			order = 0;
 			for (const iPanduan of duanluo.panduan) {
 				iPanduan.type = 'panduan';
-				iPanduan.marked = data.biaoji[iPanduan.stId] ? true: false;
+				iPanduan.marked = data.biaoji[iPanduan.stId] ? true : false;
 				iPanduan.onlyNum = uIndex + 1;
 				iPanduan.order = order;
 				paragraph.qas.push(iPanduan);
@@ -593,12 +608,12 @@
 			order = 0;
 			for (const iTiankong of duanluo.tiankong) {
 				iTiankong.type = 'tiankong';
-				iTiankong.marked = data.biaoji[iTiankong.stId] ? true: false;
+				iTiankong.marked = data.biaoji[iTiankong.stId] ? true : false;
 				iTiankong.onlyNum = uIndex + 1;
 				iTiankong.order = order;
 				paragraph.qas.push(iTiankong);
 				iTiankong.iQa = iQa;
-				iTiankong.reply = new Array(iTiankong.count).fill('');;
+				iTiankong.reply = new Array(iTiankong.count).fill('');
 				uIndex++;
 				order++;
 				iQa++;
@@ -611,10 +626,67 @@
 					onlyNum: iTiankong.onlyNum
 				})
 			}
+			order = 0;
+			for (const iJianda of duanluo.jianda) {
+				iJianda.marked = data.biaoji[iJianda.stId] ? true : false;
+				iJianda.type = 'jianda';
+				iJianda.onlyNum = uIndex + 1;
+				iJianda.order = order;
+				iJianda.iQa = iQa;
+				paragraph.qas.push(iJianda);
+				iJianda.reply = '';
+				uIndex++;
+				order++;
+				iQa++;
+
+				data.StListForSearch.push({
+					stId: iJianda.stId,
+					paragraphName: paragraph.name,
+					dlIndex: iDuanluo,
+					dtIndex: iJianda.iQa,
+					onlyNum: iJianda.onlyNum
+				})
+			}
+			order = 0;
+			for (const iYuedu of duanluo.yuedu) {
+				iYuedu.marked = data.biaoji[iYuedu.stId] ? true : false;
+				iYuedu.type = 'yuedu';
+				iYuedu.onlyNum = uIndex + 1;
+				iYuedu.order = order;
+				iYuedu.iQa = iQa;
+
+				if (iYuedu.duoxuan && iYuedu.duoxuan.length) {
+					iYuedu.duoxuan.map((qIt) => {
+						qIt.reply = qIt.reply || [];
+						return qIt
+					})
+				}
+				
+				if (iYuedu.tiankong && iYuedu.tiankong.length) {
+					iYuedu.tiankong.map((qIt) => {
+						qIt.reply = new Array(qIt.count).fill('');
+						return qIt;
+					}) ;
+				}
+
+
+
+				paragraph.qas.push(iYuedu);
+				iYuedu.reply = [];
+				uIndex++;
+				order++;
+				iQa++;
+
+				data.StListForSearch.push({
+					stId: iYuedu.stId,
+					paragraphName: paragraph.name,
+					dlIndex: iDuanluo,
+					dtIndex: iYuedu.iQa,
+					onlyNum: iYuedu.onlyNum
+				})
+			}
 			iDuanluo++;
 			questionData.value.push(paragraph)
-			console.log('1', questionData.value)
-			console.log('2', data.StListForSearch)
 		}
 	}
 
@@ -635,7 +707,10 @@
 	function formatKaoshiData() {
 		const historyData = getCacheKs(data.operId);
 		if (historyData) {
-			const { replyList ,position } = historyData;
+			const {
+				replyList,
+				position
+			} = historyData;
 			if (replyList) {
 				questionData.value.forEach(dl => {
 					dl.qas.forEach(st => {
@@ -647,7 +722,7 @@
 				progress.dlIndex = position.dlIndex;
 				progress.dtIndex = position.dtIndex;
 			}
-		
+
 		}
 	}
 
@@ -661,7 +736,6 @@
 	function initKaoshi() {
 		ksApi.getClientKsStart({
 			ksId: data.ksId,
-			userKaozhengId: data.userKaozhengId
 		}).then(res => {
 			const {
 				ksId,
@@ -683,7 +757,7 @@
 			data.ksName = ksName;
 			data.stTotal = stTotal;
 			data.stScore = stScore;
-			data.biaoji = biaoji ? JSON.parse(biaoji): {};
+			data.biaoji = biaoji ? JSON.parse(biaoji) : {};
 			data.endSecond = endSecond;
 			data.pageSize = pageSize;
 			data.toggleScreenFlag = toggleScreenFlag;
@@ -694,28 +768,113 @@
 			// 设置缓存
 			formatKaoshiData();
 			// 设置抓拍监听
-			
+
 			if (data.zhuapai && data.zhuapai > 0) {
 				zhuapaiRef.value.init({
 					zhuapai: zhuapai,
 					operId: operId
 				});
 			}
-			
+
 			// 设置切屏监听
-			qiepingRef.value.init({
-				zhuapaiFlag: true,
-				toggleScreenFlag: toggleScreenFlag,
-				toggleScreenSecond: toggleScreenSecond,
-				ksId: data.ksId
-			})
+			// qiepingRef.value.init({
+			// 	zhuapaiFlag: true,
+			// 	toggleScreenFlag: toggleScreenFlag,
+			// 	toggleScreenSecond: toggleScreenSecond,
+			// 	ksId: data.ksId
+			// })
 
-			uni.setNavigationBarTitle({
-				title: data.ksName
-			});
 			startCountDown.value = true;
 		}).catch(err => {
-      handleBack()
-    })
+			console.log('asdasd', err)
+			// handleBack()
+		})
+	}
+</script>
+
+<style lang="scss">
+	.phone-kaoshi-page {
+		display: flex;
+		flex-direction: column;
+		background-color: #f4f6fa;
+		position: relative;
+
+		.kaoshi-page-title {
+			height: 80rpx;
+			line-height: 80rpx;
+			background-color: #fff;
+			margin-top: 20rpx;
+			font-size: 26rpx;
+			color: #333;
+			display: flex;
+			justify-content: space-between;
+			padding: 0 24rpx;
+			border-bottom: 1rpx solid #ebebeb;
+
+			.title-types {
+				font-size: 32rpx;
+				color: #000;
+			}
+		}
+
+		.kaoshi-shiti-content {
+			padding: 24rpx 24rpx 0 24rpx;
+			background-color: #fff;
+			flex: 1;
+		}
+
+		.kaoshi-bottom-box {
+			width: 100%;
+			height: 100rpx;
+			background-color: #f0f0f0;
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+			padding: 0 24rpx;
+			box-sizing: border-box;
+			position: fixed;
+			bottom: var(--window-bottom);
+
+			.bj-btn,
+			.jx-btn,
+			.save-btn {
+				height: 60rpx;
+				line-height: 58rpx;
+				box-sizing: border-box;
+			}
+
+			.bj-btn {
+				margin-left: unset;
+			}
+
+			.jx-btn,
+			.save-btn {
+				margin-right: unset;
+			}
+
+			.shiti-num-icon {
+				width: 27px;
+				height: 24px;
+				vertical-align: middle;
+				// background-image: url("@/static/images/exam/shiti-num-icon.png");
+				@include ezy-no-repeat-cover();
+			}
+
+			.active-num {
+				color: #30c190;
+			}
+		}
+
+		.ks-btn-prev {
+			position: fixed;
+			bottom: 130rpx;
+			left: 24rpx;
+		}
+
+		.ks-btn-next {
+			position: fixed;
+			bottom: 130rpx;
+			right: 24rpx;
+		}
 	}
-</script>
+</style>

+ 53 - 0
pages/exam/examTools.js

@@ -0,0 +1,53 @@
+import {
+	useUserCache
+} from "@/utils/userCache.js"
+
+// 身份确认缓存
+const identificationKey = 'ShenFenQueRen'
+export function useIdentificationTools() {
+	const {saveCache,getCache,removeCache} = useUserCache();
+	
+	function saveIdentCache(key,data) {
+		saveCache(identificationKey,key, data)
+	}
+
+	function getIdentCache(key) {
+		return getCache(identificationKey, key)
+	}
+
+	function removeIdentCache(key) {
+		removeCache(identificationKey,key)
+	}
+
+
+	return {
+		saveIdentCache,
+		getIdentCache,
+		removeIdentCache
+	}
+}
+
+
+const ksCache = 'kaoshiCache'
+export function useKaoShiCache() {
+	const {saveCache,getCache,removeCache} = useUserCache();
+	
+	function saveCacheKs(key,data) {
+		saveCache(ksCache,key, data)
+	}
+	
+	function getCacheKs(key) {
+		return getCache(ksCache, key)
+	}
+	
+	function removeCacheKs(key) {
+		removeCache(ksCache,key)
+	}
+	
+	
+	return {
+		saveCacheKs,
+		getCacheKs,
+		removeCacheKs
+	}
+}

+ 41 - 3
pages/exam/index.vue

@@ -31,9 +31,47 @@
 	]
 	
 	function handleClick(data) {
-		uni.redirectTo({
-			url: '/pages/exam/exam'
-		})
+		console.log('data', data)
+		if (data.status == 0) {
+			// 未开始
+			uni.redirectTo({
+				url: `/pages/exam/exam?ksId=${data.ksId}&zhuapai=${data.zhuapai}`
+			})
+		}
+		if (data.status == 1) {
+			// 可以考试
+			uni.redirectTo({
+				url: `/pages/exam/exam?ksId=${data.ksId}&zhuapai=${data.zhuapai}`
+			})
+		}
+		if (data.status == 2) {
+			// 再次考试
+			uni.redirectTo({
+				url: `/pages/exam/exam?ksId=${data.ksId}&zhuapai=${data.zhuapai}`
+			})
+		}
+		if (data.status == 3) {
+			// 考试中
+			uni.redirectTo({
+				url: `/pages/exam/exam?ksId=${data.ksId}&zhuapai=${data.zhuapai}`
+			})
+		}
+		if (data.status == 4) {
+			// 已结束
+		}
+		if (data.status == 5) {
+			// 未报名
+		}
+		if (data.status == 6) {
+			// 报名审核中
+		}
+		if (data.status == 7) {
+			// 审核未通过
+		}
+		if (data.status == 8) {
+			// 等待人工评分
+		}
+
 	}
 </script>
 

+ 15 - 0
store/zhuapai.js

@@ -0,0 +1,15 @@
+import { defineStore } from 'pinia';
+
+export const useZhuapaiStore = defineStore('zhuapai', {
+	state: () => {
+		return { status: 0,showV:true };
+	},
+	actions: {
+		setStatus(data) {
+			this.status = data;
+		},
+		setShowV(data) {
+			this.showV = data;
+		}
+	},
+});

+ 6 - 0
uni_modules/c-progress-circle/changelog.md

@@ -0,0 +1,6 @@
+## 1.0.2(2023-04-13)
+新增boderWidth属性 可设置边框宽度
+## 1.0.1(2023-03-27)
+兼容vue2
+## 1.0.0(2023-01-05)
+初次提交

+ 185 - 0
uni_modules/c-progress-circle/components/c-progress-circle/c-progress-circle.vue

@@ -0,0 +1,185 @@
+<template>
+	<view class='container' :style="{width:size,height:size}">
+		<view class="left">
+			<view class="leftcircle" :style="leftcircleStyle">
+			</view>
+		</view>
+		<view class="right">
+			<view class="rightcircle" :style="rightcircleStyle"></view>
+		</view>
+		<view class="cneter-box">
+			<slot>
+				{{progress*100}}%
+			</slot>
+		</view>
+	</view>
+</template>
+<script>
+	/**
+	 * c-lockScreen 环形进度条
+	 * @property {Number} progress 进度 0-1 默认0
+	 * @property {String} color 进度条颜色 默认#3ec3c1
+	 * @property {String} size 进度条尺寸 单位rpx 默认200rpx
+	 * @property {String} boderWidth 边框宽度 单位rpx 默认200rpx
+	 * */
+	 export default {
+	 	props:{
+			progress: {
+				type: Number,
+				default: 0
+			},
+			color: {
+				type: String,
+				default: '#3ec3c1'
+			},
+			size: {
+				type: String,
+				default: "200rpx"
+			},
+			boderWidth:{
+				type: String,
+				default: "200rpx"
+			}
+		},
+		computed:{
+			leftcircleStyle(){
+				return `border-width: calc(${this.boderWidth} * 0.1);
+				border-bottom-color:${this.color};
+				border-left-color:${this.color};
+				transform: rotate(${this.leftAngle});
+				`
+			},
+			rightcircleStyle(){
+				return `border-width: calc(${this.boderWidth} * 0.1);
+				border-top-color:${this.color};
+				border-right-color:${this.color};
+				transform: rotate(${this.rightAngle});`
+			},
+			rightAngle(){
+				if (this.progress >= 0.5) {
+					return 45+'deg'
+				} else {
+					return -135 + 180 * this.progress * 2+'deg'
+				}
+			},
+			leftAngle(){
+				if (this.progress < 0.5) {
+					return -135+'deg'
+				} else {
+					return -315 + 180 * this.progress * 2+'deg'
+				}
+			}
+		}
+	 }
+</script>
+<style lang="scss" scoped>
+	view{
+		box-sizing: border-box;
+	}
+	.container {
+		display: flex;
+		position: relative;
+		// width: v-bind(size);
+		// height: v-bind(size);
+		.left {
+			width: 50%;
+			height: 100%;
+			position: relative;
+			overflow: hidden;
+			top: 0;
+			left: 0;
+
+			.leftcircle {
+				width: 200%;
+				height: 100%;
+				border-color:white;
+				border-style: solid;
+				position: absolute;
+				border-radius: 50%;
+				left: 0px;
+				top: 0px;
+				transition: transform 0.2s;
+				//vue3
+				// border-width: calc(v-bind(size) * 0.1);
+				// border-bottom-color:v-bind(color);
+				// border-left-color:v-bind(color);
+				// transform: rotate(v-bind(leftAngle));
+
+				// animation-name: circle_left;
+				// animation-duration: 2s;
+				// animation-timing-function: linear;
+				// animation-iteration-count: infinite;
+
+			}
+
+		}
+
+		.right {
+			width: 50%;
+			height: 100%;
+			position: relative;
+			overflow: hidden;
+			top: 0;
+			right: 0;
+		}
+
+		.rightcircle {
+			width: 200%;
+			height: 100%;
+			border-radius: 50%;
+			border-color:white;
+			border-style: solid;
+			position: absolute;
+			
+			right: 0px;
+			top: 0px;
+			// animation-name: circle_right;
+			// animation-duration: 2s;
+			// animation-timing-function: linear;
+			// animation-iteration-count: infinite;
+			transition: transform 0.2s;
+			//vue3
+			// border-width: calc(v-bind(size) * 0.1);
+			// border-top-color:v-bind(color);
+			// border-right-color:v-bind(color);
+			// transform: rotate(v-bind(rightAngle));
+		}
+		.cneter-box{
+			position: absolute;
+			width: 100%;
+			height: 100%;
+			font-size: 24rpx;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+		}
+	}
+
+
+
+
+
+
+	// @keyframes circle_right {
+	// 	0% {
+	// 		transform: rotate(-135deg);
+	// 	}
+
+	// 	50%,
+	// 	100% {
+	// 		transform: rotate(45deg);
+	// 	}
+	// }
+
+	// @keyframes circle_left {
+
+	// 	0%,
+	// 	50% {
+	// 		transform: rotate(-135deg);
+	// 	}
+
+	// 	100% {
+	// 		transform: rotate(45deg);
+	// 	}
+	// }
+</style>

+ 82 - 0
uni_modules/c-progress-circle/package.json

@@ -0,0 +1,82 @@
+{
+  "id": "c-progress-circle",
+  "displayName": "c-design c-progress-circle",
+  "version": "1.0.2",
+  "description": "环形进度条",
+  "keywords": [
+    "c-progress-circle",
+    "环形进度条"
+],
+  "repository": "https://gitee.com/wangziwl/c-designc.git",
+  "engines": {
+    "HBuilderX": "^3.6.15"
+  },
+  "dcloudext": {
+    "type": "component-vue",
+    "sale": {
+      "regular": {
+        "price": "0.00"
+      },
+      "sourcecode": {
+        "price": "0.00"
+      }
+    },
+    "contact": {
+      "qq": ""
+    },
+    "declaration": {
+      "ads": "无",
+      "data": "无",
+      "permissions": "无"
+    },
+    "npmurl": ""
+  },
+  "uni_modules": {
+    "dependencies": [],
+    "encrypt": [],
+    "platforms": {
+      "cloud": {
+        "tcb": "y",
+        "aliyun": "y"
+      },
+      "client": {
+        "Vue": {
+          "vue2": "y",
+          "vue3": "y"
+        },
+        "App": {
+          "app-vue": "y",
+          "app-nvue": "n"
+        },
+        "H5-mobile": {
+          "Safari": "y",
+          "Android Browser": "y",
+          "微信浏览器(Android)": "y",
+          "QQ浏览器(Android)": "y"
+        },
+        "H5-pc": {
+          "Chrome": "y",
+          "IE": "u",
+          "Edge": "y",
+          "Firefox": "y",
+          "Safari": "y"
+        },
+        "小程序": {
+          "微信": "y",
+          "阿里": "u",
+          "百度": "u",
+          "字节跳动": "u",
+          "QQ": "u",
+          "钉钉": "u",
+          "快手": "u",
+          "飞书": "u",
+          "京东": "u"
+        },
+        "快应用": {
+          "华为": "u",
+          "联盟": "u"
+        }
+      }
+    }
+  }
+}

+ 98 - 0
uni_modules/c-progress-circle/readme.md

@@ -0,0 +1,98 @@
+# c-progress-circle
+
+### 
+- c-progress-circle 环形进度条
+
+### c-design交流群号:330647926
+
+### 示例预览
+[https://cloud.vuedata.wang/cdesign/#/pages/progress-circle/progress-circle](https://cloud.vuedata.wang/cdesign/#/pages/progress-circle/progress-circle)
+
+### 一、使用示例
+```html
+<template>
+	<view class="content">
+		<c-progress-circle :progress='progress' :color='color' :size='size' :boderWidth="boderWidth"></c-progress-circle>
+		<view class="btnBox">
+			<button size="mini" @click="add">+</button>
+			<view style="width: 100rpx;text-align: center;">
+				{{progress}}
+			</view>
+			<button size="mini" @click="reduce" type="default">-</button>
+		</view>
+		<view class="btnBox" style="padding-left: 100rpx;">边框颜色</view>
+		<view class="btnBox">
+			<button size="mini" @click="color='red'">红色</button>
+			<button size="mini" @click="color='green'">绿色</button>
+			<button size="mini" @click="color='orange'">橙色</button>
+		</view>
+		<view class="btnBox" style="padding-left: 100rpx;">进度条尺寸</view>
+		<view class="btnBox">
+			<button size="mini" @click="size='200rpx'">200rpx</button>
+			<button size="mini" @click="size='400rpx'">400rpx</button>
+			<button size="mini" @click="size='600rpx'">600rpx</button>
+		</view>
+		<view class="btnBox" style="padding-left: 100rpx;">边框宽度</view>
+		<view class="btnBox">
+			<button  size="mini" @click="boderWidth='200rpx'">200rpx</button>
+			<button  size="mini" @click="boderWidth='400rpx'">400rpx</button>
+			<button  size="mini" @click="boderWidth='600rpx'">600rpx</button>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				progress: 0.2,
+				color:'red',
+				size:'200rpx',
+				boderWidth:'200rpx'
+			}
+		},
+		methods: {
+			add() {
+				if(this.progress<1){
+					this.progress +=0.1
+					this.progress=this.progress.toFixed(1)*1
+				}
+			},
+			reduce(){
+				if(this.progress>0){
+					this.progress -=0.1
+					this.progress=this.progress.toFixed(1)*1	
+				}
+			}
+		},
+	}
+</script>
+
+<style lang="scss">
+	.content{
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		padding-top: 20rpx;
+		font-size: 28rpx;
+	}
+	.btnBox{
+		width: 100%;
+		display: flex;
+		align-items: center;
+		margin-top:30rpx;
+	}
+</style>
+```
+
+
+
+
+### 二、属性介绍
+
+| 字段			| 类型		| 必填	| 默认值				| 描述								|
+| -----------	| --------	| ----	| ----------------------| -------------------------------	|
+| progress		| Number	| 否	|  0					| 进度 0-1							|
+| color			| String	| 否	|  #3ec3c1				| 进度条颜色						|
+| size			| String	| 否	|  200rpx				| 进度条尺寸 单位rpx				|
+| boderWidth	| String	| 否	|  200rpx				| 边框宽度 单位rpx					|

+ 143 - 0
utils/cacheManager.js

@@ -0,0 +1,143 @@
+const cacheManager = (function() {
+	const STORAGE_PREFIX = 'App_cache_';
+
+	function set(key, value) {
+		const fullKey = STORAGE_PREFIX + key;
+		if (typeof value === 'object' && value !== null) {
+			// 如果是对象,则将其转换为字符串存储
+			uni.setStorageSync(fullKey, JSON.stringify(value));
+		} else {
+			uni.setStorageSync(fullKey, value);
+		}
+	}
+
+	// 获取缓存
+	function get(key) {
+		const fullKey = STORAGE_PREFIX + key;
+		const value = uni.getStorageSync(fullKey);
+		try {
+			return JSON.parse(value);
+		} catch (e) {
+			return value;
+		}
+	}
+
+	// 删除缓存
+	function remove(key) {
+		const fullKey = STORAGE_PREFIX + key;
+		uni.removeStorageSync(fullKey);
+	}
+
+	//例子: cacheManager.updateObject('user', { www: undefined }); //删除
+	function updateObject(key, updates) {
+		let obj = get(key) || {};
+		// 合并更新到对象中
+		//Object.assign(obj, updates);
+		for (let [keyToUpdate, value] of Object.entries(updates)) {
+			if (value === null || value === undefined) {
+				// 如果值为 null 或 undefined,则删除属性
+				delete obj[keyToUpdate];
+			} else {
+				obj[keyToUpdate] = value;
+			}
+		}
+		set(key, obj);
+	}
+	// 用于视频已经看完 修改状态
+	function updateJieStatus(key, index, currentJieId) {
+		let obj = get(key) || {};
+		for (let jie of obj.zhangList[index].jieList) {
+			if (jie.jieId == currentJieId) {
+				//		console.log('jie',jie);
+				jie.studyFlag = 1
+				break
+			}
+		}
+		set(key, obj);
+	}
+	// 更新会员
+	function updateVipStatus(key, cardId) {
+		let obj = get(key) || {};
+		if (!obj.cardList.includes(cardId)) {
+			obj.cardList.push(Number(cardId));
+		}
+		set(key, obj);
+	}
+	// 获得当前jie参数
+	function getCurrentJieData(key, index, currentJieId) {
+		let obj = get(key) || {};
+		for (let jie of obj.zhangList[index].jieList) {
+			if (jie.jieId == currentJieId) {
+				return jie
+				break
+			}
+		}
+	}
+
+	function clearAll() {
+		const keys = uni.getStorageInfoSync().keys;
+		keys.forEach(key => {
+			if (key.startsWith(STORAGE_PREFIX)) {
+				uni.removeStorageSync(key);
+			}
+		});
+	}
+
+	// 增量修改对象中的数组,支持添加、更新和删除元素
+	function updateArrayInObject(key, arrayPath, updateFn) {
+		let obj = get(key) || {};
+
+		// 根据arrayPath找到需要修改的数组
+		const targetArray = findArrayInObject(obj, arrayPath);
+
+		if (Array.isArray(targetArray)) {
+			// 应用更新函数到目标数组上
+			updateFn(targetArray);
+
+			// 重新设置缓存
+			set(key, obj);
+		} else {
+			console.error(`${arrayPath}不指向对象中的数组。`);
+		}
+	}
+	//  例子
+	// cacheManager.updateArrayInObject('user', 'hobbies', (hobbies) => {
+	// 	hobbies.push('reading');
+	// 	hobbies = 'coding';
+	// 	hobbies.pop();
+	// });
+	// 在对象中根据路径找到数组
+	function findArrayInObject(obj, path) {
+		return path.split('.').reduce((acc, curr) => {
+			if (acc && acc[curr] !== undefined) {
+				return acc[curr];
+			} else {
+				return undefined;
+			}
+		}, obj);
+	}
+	return {
+		set,
+		get,
+		remove,
+		updateJieStatus,
+		getCurrentJieData,
+		updateObject,
+		updateVipStatus,
+		findArrayInObject,
+		clearAll
+	};
+})();
+
+export default cacheManager;
+
+// 单元测试 引导大鹅提示 缓存Key
+export const SHOW_UNIT_TEST_TISHI = 'SHOW_UNIT_TEST_TISHI';
+
+// 单元测试大鹅提示缓存
+export function useUnitTestTishi() {
+	return {
+		updateTishi: () => cacheManager.set(SHOW_UNIT_TEST_TISHI, 'has'),
+		getTishi: () => cacheManager.get(SHOW_UNIT_TEST_TISHI)
+	}
+}

+ 136 - 0
utils/userCache.js

@@ -0,0 +1,136 @@
+import cacheManager from "@/utils/cacheManager.js"
+
+const TokenKey = 'Mta-UserCache'
+
+export function useUserCache() {
+	function saveCache() {
+		let pageId, key, value;
+		if (arguments.length === 3) {
+			pageId = arguments[0];
+			key = arguments[1];
+			value = arguments[2];
+		} else if (arguments.length === 2) {
+			pageId = arguments[0];
+			key = 'default';
+			value = arguments[1];
+		} else {
+			console.log('saveCache 参数非法');
+			return;
+		}
+
+		const auth = cacheManager.get('auth');
+		// console.log('auth:', auth)
+		if (!auth) {
+			throw new Error('用户未登录!')
+			return;
+		}
+		const userId = auth.userId;
+		// console.log('userId:', userId)
+		if (!userId) {
+			throw new Error('数据异常用户Id异常!')
+			return;
+		}
+		
+		let pageData = uni.getStorageSync(TokenKey);
+		if (!pageData) {
+			pageData = {};
+		}
+		if (!pageData[userId]) {
+			pageData[userId] = {};
+		}
+		if (!pageData[userId][pageId]) {
+			pageData[userId][pageId] = {};
+		}
+		let oriVal = pageData[userId][pageId][key];
+		if (oriVal !== null && !Array.isArray(oriVal) && typeof oriVal === 'object') {
+			Object.assign(oriVal, value);
+			pageData[userId][pageId][key] = oriVal;
+		} else {
+			pageData[userId][pageId][key] = value;
+		}
+		pageData[userId][pageId]['markTime'] = new Date().getTime();
+		uni.setStorageSync(TokenKey, pageData)
+	}
+
+	function getCache() {
+		let pageId, key;
+		if (arguments.length === 2) {
+			pageId = arguments[0];
+			key = arguments[1];
+		} else if (arguments.length === 1) {
+			pageId = arguments[0];
+			key = 'default';
+		} else {
+			console.log('getCache 参数非法');
+			return;
+		}
+
+		const auth = cacheManager.get('auth');
+		if (!auth) {
+			throw new Error('用户未登录!')
+			return;
+		}
+		const userId = auth.userId;
+		if (!userId) {
+			throw new Error('数据异常用户Id异常!')
+			return;
+		}
+
+		let pageData = uni.getStorageSync(TokenKey);
+		if (!pageData || !pageData[userId] || !pageData[userId][pageId]) {
+			return null;
+		}
+		return pageData[userId][pageId][key];
+	}
+
+	function removeCache() {
+		let pageId, key;
+		if (arguments.length === 2) {
+			pageId = arguments[0];
+			key = arguments[1];
+		} else if (arguments.length === 1) {
+			pageId = arguments[0];
+		} else {
+			console.log('removeCache 参数非法');
+			return;
+		}
+
+		const auth = cacheManager.get('auth');
+		if (!auth) {
+			throw new Error('用户未登录!')
+			return;
+		}
+		const userId = auth.userId;
+		if (!userId) {
+			throw new Error('数据异常用户Id异常!')
+			return;
+		}
+
+		if (pageId) {
+			let pageData = uni.getStorageSync(TokenKey);
+			if (!pageData) {
+				return;
+			}
+			if (!pageData[userId]) {
+				return;
+			}
+			if (arguments.length === 1) {
+				delete pageData[userId][pageId];
+				uni.setStorageSync(TokenKey, pageData)
+
+			} else if (arguments.length === 2) {
+				if (!pageData[userId][pageId]) {
+					return;
+				}
+				delete pageData[userId][pageId][key];
+				uni.setStorageSync(TokenKey, pageData)
+			}
+		}
+	}
+
+	return {
+		saveCache,
+		getCache,
+		removeCache
+	}
+}