Ver Fonte

课程考试练习

wangxy há 2 meses atrás
pai
commit
aaeaa52393

+ 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.lxId);
+		popupRef.value.close()
+	}
+
+	defineExpose({
+		showDialog
+	})
+</script>
+
+<style lang="scss">
+
+</style>

+ 60 - 31
components/kecheng-mulu/kecheng-mulu.vue

@@ -1,52 +1,81 @@
 <template>
 	<view class="kecheng-mulu">
-	<!-- 章collapse -->
-		<uni-collapse v-model="collapse.chapterActiveName" accordion>
-				<!-- 章 -->
-			<uni-collapse-item v-for="(chapter,i) in chapterArr" :key="i"
-				:title="chapter.name" :name="chapter.i">
-				<scroll-view :scroll-y="true" :style="{ height: 100*5+'rpx' }">
-					<!-- 节collapse -->
-					<uni-collapse v-model="collapse.sectionActiveName" accordion>
-						<!-- 节 -->
-						<uni-collapse-item v-for="(section,j) in chapter.jieList" :key="j"
-							:title="section.name" :name="section.j">
-							<view>asdasd</view>
-							<text>123asdasd</text>
-						</uni-collapse-item>
-					</uni-collapse>
-				</scroll-view>
-			</uni-collapse-item>
-		</uni-collapse>
+		<myCollapseCardVue v-for="zhang in chapterArr" :title="zhang.name" @click.stop="handleZhangClick(zhang)"
+			:open="zhang.open">
+			<myCollapseCardVue v-for="jie in zhang.jieList" :title="jie.name" @click.stop="handleJieClick(jie, zhang)"
+				:open="jie.open">
+				<view class="kejian-item" v-for="item in jie.kejianList" @click.stop="handleKejianClick(item)">
+					<text>{{item.name}}</text>
+					<text v-if="isHasProgress">进度{{item.curProcess}}</text>
+				</view>
+			</myCollapseCardVue>
+		</myCollapseCardVue>
 	</view>
 </template>
 
 <script setup>
+	import myCollapseCardVue from '../myCollapseCard/myCollapseCard.vue';
 	import {
-		reactive,
 		ref
 	} from 'vue';
-	defineProps({
+	const props = defineProps({
 		chapterArr: {
-			type: Array,
-			default: () => ([])
+			type: Array
+		},
+		isHasProgress: {
+			type: Boolean
 		}
 	})
 
-	const collapse = reactive({
-		chapterActiveName: '0',
-		sectionActiveName: '0',
-	})
+	const emits = defineEmits(['play'])
 
-	const historyKjId = ref('')
+	function handleZhangClick(item) {
 
-	function handleClick() {}
+		if (item.open) {
+			// 展开 -》 关闭
+			props.chapterArr.forEach(zhang => {
+				zhang.open = false;
+				zhang.jieList.forEach(jie => {
+					jie.open = false;
+				})
+			})
+		} else {
+			// 关闭 -》 展开
+			props.chapterArr.forEach(zhang => {
+				zhang.open = false;
+				zhang.jieList.forEach(jie => {
+					jie.open = false;
+				})
+			})
+			item.open = true;
+		}
+	}
 
-	function getClassByType() {}
+	function handleJieClick(item, zhang) {
+		if (item.open) {
+			// 展开 -》 关闭
+			zhang.jieList.forEach(jie => {
+				jie.open = false;
+			})
+		} else {
+			// 关闭 -》 展开
+			zhang.jieList.forEach(jie => {
+				jie.open = false;
+			})
+			item.open = true;
+		}
+	}
 
-	function shitiClick() {}
+	function handleKejianClick(item) {
+		emits('play', item)
+	}
 </script>
 
-<style>
 
+
+
+<style>
+	.kejian-item {
+		line-height: 50px;
+	}
 </style>

+ 41 - 0
components/myCollapseCard/myCollapseCard.vue

@@ -0,0 +1,41 @@
+<template>
+	<view class="my-collapse-card">
+		<view class="my-collapse-item">{{title}} --- {{open}}</view>
+		<view class="my-card-content" :class="{'card-open': open}">
+			<slot></slot>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: "myCollapseCard",
+		props: {
+			title: {
+				type: String
+			},
+			open: {
+				type:Boolean
+			}
+		},
+	}
+</script>
+
+<style lang="scss">
+	.my-collapse-item {
+		height: 60rpx;
+		line-height: 60rpx;
+		background-color: #cc2;
+	}
+
+	.my-card-content {
+		height: 0rpx;
+		overflow: hidden;
+		margin: 0 5px;
+	}
+	.card-open {
+		display: block;
+		height: auto;
+		background: #ccc;
+	}
+</style>

+ 1 - 1
components/password-lli/password-lli.vue

@@ -42,7 +42,7 @@
 			if (window.lli && typeof window.lli.encode === 'function') {
 			} else {
 				const script = document.createElement('script')
-				script.src = 'static/encode.js'
+				script.src = '/mdist/static/encode.js'
 				document.head.appendChild(script)
 			}
 		},

+ 44 - 0
components/scoreAndAnswer/scoreAndAnswerAdminTiankong.vue

@@ -0,0 +1,44 @@
+<template>
+	<uni-popup ref="popupRef" background-color="#fff" >
+		<view class="phone-question-answer-box">
+			<view class="phone-line-title">答案解析</view>
+			<view class="btdf-row">本题得分:<text>{{data.score}}</text>分</view>
+			<view class="zqda-row">正确答案:
+				<view v-for="(item,index) in data.result">{{`填空${index+1}`}} : {{item}}</view>
+			</view>
+			<view class="ndda-row">您的答案:
+			<view v-for="(item,index) in data.reply"> {{`填空${index+1}`}}: {{item}}</view>
+			</view>
+			<view class="dajx-row">答案解析: 
+				<rich-text :nodes="data.answer"></rich-text>
+			</view>
+		</view>
+	</uni-popup>
+</template>
+
+<script setup>
+	import {ref,reactive} from "vue";
+	const popupRef = ref('popupRef');
+	const data = reactive({
+		score: 0,
+		reply: '',
+		result: '',
+		answer: '',
+	})
+	
+	function showPopup(options) {
+		console.log('options',options)
+		data.score = options.score;
+		data.reply = options.reply;
+		data.result = options.result;
+		data.answer = options.answer;
+		
+		popupRef.value.open('bottom')
+	}
+	
+	defineExpose({showPopup})
+</script>
+
+<style>
+
+</style>

+ 1 - 1
manifest.json

@@ -147,7 +147,7 @@
     "vueVersion" : "3",
     "h5" : {
         "router" : {
-            "base" : "/",
+            "base" : "/mdist",
             "mode" : "history"
         },
         "title" : "北京诚祥",

+ 7 - 0
pages.json

@@ -80,6 +80,13 @@
 			{
 				"navigationStyle": "custom"
 			}
+		},
+		{
+			"path" : "pages/admin/Lianxi/lianxi",
+			"style" : 
+			{
+				"navigationStyle": "custom"
+			}
 		}
 	],
 	 "tabBar": {

+ 23 - 9
pages/admin/Kaoshi/exam.vue

@@ -47,6 +47,7 @@
 		<template v-if="activeSt">
 			<button type="default" size="mini" hover-class="none" class="phone-green-btn ks-btn-prev" @click="handlePrev" v-if="!isFistStId">上一题</button>
 			<button type="default" size="mini" hover-class="none"class="phone-green-btn ks-btn-next" @click="handleNext" v-if="!isLastStId">下一题</button>
+			<button type="default" size="mini" hover-class="none"class="phone-green-btn ks-btn-next" @click="handleBack" v-if="isLastStId">交卷</button>
 		</template>
 
 		<!-- 答题卡 -->
@@ -75,7 +76,7 @@
 		-->
 		<!-- 答案解析 -->
 		<scoreAndAnswerVue ref="scoreAnswerRef"></scoreAndAnswerVue>
-		
+		<scoreAndAnswerAdminTiankong ref="scoreAnswerTkRef"></scoreAndAnswerAdminTiankong>
 	</view>
 
 
@@ -99,7 +100,7 @@
 	import panduan from "@/components/questions/panduan.vue";
 	import scoreAndAnswerVue from "@/components/scoreAndAnswer/scoreAndAnswerAdmin.vue";
 	import {useQuestionTools} from "@/components/questions/useQuestionTools.js";
-
+	import scoreAndAnswerAdminTiankong from "@/components/scoreAndAnswer/scoreAndAnswerAdminTiankong.vue";
 	const {
 		checkDanxuanReply,
 		checkDuoxuanReply,
@@ -117,6 +118,7 @@
 
 	const popupRef = ref(null)
 	const scoreAnswerRef = ref(null)
+	const scoreAnswerTkRef = ref(null)
 
 	const startCountDown = ref(false);
 
@@ -376,28 +378,36 @@
 			// 单选题
 			if (qa.reply && qa.reply.trim() !== '') {
 				reply = getLetterByIndex(qa.reply)
+			} else {
+				reply = '未答'
 			}
 			
 			if (qa.result) {
 				result = getLetterByIndex(qa.result)
+			} else {
+				result = '无答案'
 			}
 		}
 		if (qa.stTypeId == 2) {
 			// 多选题
 			
 			if (qa.reply && qa.reply.length) {
-				reply = reply.map(item => {
+				reply = qa.reply.map(item => {
 					if (item.trim()) {
 						return getLetterByIndex(item.trim())
 					}
-				})
+				}).join(',')
+			} else {
+				reply = '未答'
 			}
 			if (qa.result) {
-				result = result.map(item => {
+				result = qa.result.map(item => {
 					if (item.trim()) {
 						return getLetterByIndex(item.trim())
 					}
-				})
+				}).join(',')
+			} else {
+				result = '无答案'
 			}
 		}
 		if (qa.stTypeId == 3) {
@@ -414,11 +424,15 @@
 			}
 		}
 		if (qa.stTypeId == 4) {
+			let reply = qa.reply || [];
+			let result =qa.result || [];
 			// 填空题
+			scoreAnswerTkRef.value.showPopup({score,reply,result,answer})
+		} else {
+			scoreAnswerRef.value.showPopup({
+				score,reply,result,answer
+			})
 		}
-		scoreAnswerRef.value.showPopup({
-			score,reply,result,answer
-		})
 	}
 
 	function initKaoshi() {

+ 60 - 10
pages/admin/Kecheng/study.vue

@@ -13,19 +13,19 @@
 		</view>
 		<!-- 大纲 -->
 		<view class="uni-padding-wrap uni-common-mt">
-			<uni-segmented-control :current="current" :values="items" style-type="text"
-				:active-color="activeColor" @clickItem="onClickItem" />
+			<uni-segmented-control :current="current" :values="items" style-type="text" :active-color="activeColor"
+				@clickItem="onClickItem" />
 		</view>
 		<view class="content">
 			<!-- 目录 -->
 			<view v-if="current === 0">
-				<kechengMuluVue :chapterArr="list"></kechengMuluVue>
+				<kechengMuluVue :chapterArr="list" @play="handlePlay" :isHasProgress="false"></kechengMuluVue>
 			</view>
 			<!-- 介绍 -->
-			<view v-if="current === 1"><text class="content-text">选项卡2的内容</text></view>
+			<view v-if="current === 1 && intro">
+				<rich-text :nodes="intro"></rich-text>
+			</view>
 		</view>
-
-
 	</view>
 </template>
 
@@ -34,12 +34,16 @@
 	import videoPlayVue from "@/components/videoPlay/videoPlay.vue";
 	import kechengMuluVue from "@/components/kecheng-mulu/kecheng-mulu.vue";
 	import {
+		useUserCache
+	} from "@/utils/kechengCache.js"
+	import {
 		formatDuration
 	} from "@/utils/common.js"
 
 	export default {
 		components: {
-			videoPlayVue,kechengMuluVue
+			videoPlayVue,
+			kechengMuluVue
 		},
 		data() {
 			return {
@@ -52,6 +56,8 @@
 				period: 0, // 时长
 				userCount: 0, // 学习人数
 				list: [],
+				intro: '',
+				curPlayData: null
 			}
 		},
 		onLoad(options) {
@@ -69,12 +75,46 @@
 					this.current = e.currentIndex
 				}
 			},
-	
+			formatData(data) {
+				data.forEach(zhang => {
+					zhang.open = false;
+					zhang.jieList.forEach(jie => {
+						jie.open = false;
+					})
+				})
+				return data;
+			},
+			handlePlay(data) {
+				if (this.curPlayData && this.curPlayData.videoId == data.videoId) {
+					return;
+				}
+
+				// console.log('播放进度', data)
+				kechengApi.getVideoAuth({
+					videoId: data.url
+				}).then(res => {
+					// console.log('切换视频', {
+					// 	videoId: data.url,
+					// 	playAuth: res.data,
+					// 	seekTime: '',
+					// });
+					this.$refs.videoRef.init({
+						videoId: data.url,
+						playAuth: res.data,
+						seekTime: '',
+					})
+				})
+			},
+			initFirstVideo() {
+				if (this.list && this.list[0].jieList && this.list[0].jieList[0].kejianList) {
+					const kejian = this.list[0].jieList[0].kejianList[0];
+					this.handlePlay(kejian)
+				}
+			},
 			init() {
 				kechengApi.getKechengGlStart({
 					kcId: this.kcId
 				}).then(res => {
-					console.log('rrr', res.data)
 					const {
 						userCount,
 						period,
@@ -85,8 +125,18 @@
 					this.userCount = userCount;
 					this.period = formatDuration(period);
 					this.name = name;
-					this.list = kejianUserVo.zhangList;
+					let testData = JSON.parse(JSON.stringify([...kejianUserVo.zhangList, ...kejianUserVo.zhangList,
+						...kejianUserVo.zhangList
+					]))
+					this.formatData(testData)
+					this.list = testData;
 					this.intro = intro;
+
+					this.initFirstVideo();
+
+					uni.setNavigationBarTitle({
+						title: this.name
+					});
 				})
 			}
 		}

+ 474 - 0
pages/admin/Lianxi/lianxi.vue

@@ -0,0 +1,474 @@
+<template>
+	<view class="phone-kaoshi-page">
+		<!-- 导航区域 -->
+		<view class="icon-title-navBar-box">
+			<view @click="handleBack" class="nav-bar-icon"></view>
+			<text class="nav-bar-title">{{data.lxName}}</text>
+		</view>
+		<!-- 第一行 -->
+		<view class="kaoshi-page-title">
+			<view v-if="activeSt" class="title-types">{{stTypes[activeSt.stTypeId]}}</view>
+			<view>100分钟</view>
+		</view>
+
+
+		<view class="kaoshi-shiti-content">
+			<!-- 内容区域 -->
+			<!-- 试题区域 -->
+			<view v-if="activeSt">
+				<template v-if="activeSt.stTypeId == 1">
+					<!-- 单选 -->
+					<danxuan :question="activeSt" :key="activeSt.stId"></danxuan>
+				</template>
+				<template v-if="activeSt.stTypeId == 2" >
+					<!-- 多选 -->
+					<duoxuan :question="activeSt" :key="activeSt.stId"></duoxuan>
+				</template>
+				<template v-if="activeSt.stTypeId == 3">
+					<!-- 判断 -->
+					<panduan :question="activeSt" :key="activeSt.stId"></panduan>
+				</template>
+				<template v-if="activeSt.stTypeId == 4">
+					<!-- 填空 -->
+					<tiankong :question="activeSt" :key="activeSt.stId"></tiankong>
+				</template>
+			</view>
+
+		</view>
+
+		<view class="kaoshi-bottom-box">
+			<button class="phone-green-btn bj-btn" hover-class="none" type="default" size="mini" @click="handleBiaoji">标记</button>
+			<view @click="showAnswerCard" class="shiti-num-box">
+				<icon class="shiti-num-icon"></icon>
+				<text class="active-num">{{activeSt ? activeSt.onlyNum: 0}}</text>/<text>{{data.StListForSearch.length}}</text>
+			</view>
+			<button class="phone-white-btn jx-btn" hover-class="none" type="default" size="mini" @click="handleCheckJiexi">解析</button>
+		</view>
+		<template v-if="activeSt">
+			<button type="default" size="mini" hover-class="none" class="phone-green-btn ks-btn-prev" @click="handlePrev" v-if="!isFistStId">上一题</button>
+			<button type="default" size="mini" hover-class="none"class="phone-green-btn ks-btn-next" @click="handleNext" v-if="!isLastStId">下一题</button>
+					<button type="default" size="mini" hover-class="none"class="phone-green-btn ks-btn-next" @click="handleBack" v-if="isLastStId">交卷</button>
+		</template>
+
+		<!-- 答题卡 -->
+		<uni-popup ref="popupRef" background-color="#fff" :is-mask-click="false" :mask-click="false">
+			<view class="answer-card-popup">
+				<view class="icon-title-bjcolor-navBar-box">
+					<view @click="handlePopupBack" class="nav-bar-icon"> </view>
+					<text class="nav-bar-title">答题卡</text>
+				</view>
+				<view class="answer-card-content" v-for="(paragraph,paragraphIndex) in questionData" :key="paragraphIndex">
+					<view class="paragraph-title">
+						{{paragraph.name}}
+					</view>
+					<view class="paragraph-qa" v-for="(qa,qaIndex) in paragraph.qas" :key="qaIndex" 
+					:class="getQaClass(qa)" @click="answerCardItemClick(qa)">{{qa.onlyNum}}
+					</view>
+				</view>
+			</view>
+		</uni-popup>
+		<!--
+		// 倒计时
+		<view v-if="!!data.endSecond">
+			<text>考试倒计时:</text>
+			<uni-countdown :show-day="false" :second="1000" @timeup="onTimeUp" :start="startCountDown"></uni-countdown>
+		</view>
+		-->
+		<!-- 答案解析 -->
+		<scoreAndAnswerVue ref="scoreAnswerRef"></scoreAndAnswerVue>
+		<scoreAndAnswerAdminTiankong ref="scoreAnswerTkRef"></scoreAndAnswerAdminTiankong>	
+	</view>
+
+
+
+</template>
+
+<script setup>
+	import {
+		ref,
+		reactive,
+		computed,
+		watch
+	} from "vue";
+	import {
+		onLoad
+	} from "@dcloudio/uni-app";
+	import * as lxApi from "@/api/lianxi.js"
+	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 scoreAndAnswerVue from "@/components/scoreAndAnswer/scoreAndAnswerAdmin.vue";
+	import scoreAndAnswerAdminTiankong from "@/components/scoreAndAnswer/scoreAndAnswerAdminTiankong.vue";
+	import {useQuestionTools} from "@/components/questions/useQuestionTools.js";
+
+	const {
+		checkDanxuanReply,
+		checkDuoxuanReply,
+		checkPanduanReply,
+		checkTiankongReply,
+		getLetterByIndex
+	} = useQuestionTools();
+
+	const stTypes = {
+		1: '单选题',
+		2: '多选题',
+		3: '判断题',
+		4: '填空题',
+	}
+
+	const popupRef = ref(null)
+	const scoreAnswerRef = ref(null)
+	const scoreAnswerTkRef = ref(null)
+
+	const startCountDown = ref(false);
+
+	const data = reactive({
+		lxId: null,
+		lxName: '',
+		stTotal: 0,
+		stScore: 0,
+		biaoji: null,
+		endSecond: 0,
+		pageSize: 0,
+		toggleScreenFlag: 0,
+		toggleScreenSecond: 0,
+		zhuapai: 0,
+		duanluo: [],
+		markDB: [],
+		StListForSearch: [],
+	})
+
+	const questionData = ref([]);
+
+	const progress = reactive({
+		dlIndex: 0,
+		dtIndex: 0
+	})
+
+	watch(() => data.duanluo, (newVal) => {
+		// 计算已答试题数量
+	}, {
+		deep: true
+	})
+
+	const activeSt = computed(() => {
+		if (questionData.value.length) {
+			return questionData.value.length && questionData.value[progress.dlIndex].qas[progress.dtIndex];
+		} else {
+			return null
+		}
+	})
+
+	const isFistStId = computed(() => {
+		if (data.StListForSearch.length) {
+			return data.StListForSearch[0].stId == activeSt.value.stId
+		} else {
+			return false
+		}
+	});
+	const isLastStId = computed(() => {
+		if (data.StListForSearch.length) {
+			return data.StListForSearch[data.StListForSearch.length - 1].stId == activeSt.value.stId
+		} else {
+			return false
+		}
+	});
+
+	onLoad((option) => {
+		data.lxId = option.lxId;
+		initKaoshi();
+	})
+
+	function getQaClass(qa) {
+		if (qa.marked && qa.marked === true) {
+			return 'paragraph-qa-block-mark';
+		} else {
+			if (qa.stTypeId == 1) {
+				if (checkDanxuanReply(qa)) {
+					return 'paragraph-qa-block-done';
+				} else {
+					return 'paragraph-qa-block-init';
+				}
+			} else if (qa.stTypeId == 2) {
+				if (checkDuoxuanReply(qa)) {
+					return 'paragraph-qa-block-done';
+				} else {
+					return 'paragraph-qa-block-init';
+				}
+			} else if (qa.stTypeId == 3) {
+				if (checkPanduanReply(qa)) {
+					return 'paragraph-qa-block-done';
+				} else {
+					return 'paragraph-qa-block-init';
+				}
+			} else if (qa.stTypeId == 4) {
+				if (checkTiankongReply(qa)) {
+					return 'paragraph-qa-block-done';
+				} else {
+					return 'paragraph-qa-block-init';
+				}
+			}
+		}
+	}
+
+	function skipQuestion(dlIndex, dtIndex) {
+		progress.dlIndex = dlIndex;
+		progress.dtIndex = dtIndex;
+		handlePopupBack()
+	}
+
+	function answerCardItemClick(qa) {
+		const actQa = data.StListForSearch.find(item => item.stId == qa.stId);
+		skipQuestion(actQa.dlIndex, actQa.dtIndex)
+
+	}
+
+	function handleBack() {
+		uni.redirectTo({
+			url: "/pages/admin/Kaoshi/list"
+		})
+	}
+
+	function onTimeUp() {
+		console.log('end')
+	}
+
+	function showAnswerCard() {
+		popupRef.value.open('bottom')
+	}
+
+	function handlePopupBack() {
+		popupRef.value.close()
+	}
+
+	function handlePrev() {
+		const qa = data.StListForSearch.find(item => item.stId == activeSt.value.stId);
+		const index = qa.num - 1;
+		if (index > 0) {
+			const result = data.StListForSearch[index - 1];
+			progress.dlIndex = result.dlIndex;
+			progress.dtIndex = result.dtIndex
+		}
+
+	}
+
+	function handleNext() {
+		const qa = data.StListForSearch.find(item => item.stId == activeSt.value.stId);
+		const index = qa.num - 1;
+		if (index < data.StListForSearch.length) {
+			const result = data.StListForSearch[index + 1];
+			progress.dlIndex = result.dlIndex;
+			progress.dtIndex = result.dtIndex
+		}
+	}
+
+	function formatDuanluoList(dlData) {
+		let uIndex = 0; // 试题num
+		let iDuanluo = 0; // 段落num
+		let result = [];
+		for (const duanluo of data.duanluo) {
+			let paragraph = {
+				qas: [],
+			};
+			paragraph.name = duanluo.name;
+
+			let iQa = 0; // 当前试题序号
+			let order = 0; // 当前题型中第几题
+			for (const iDanxuan of duanluo.danxuan) {
+				iDanxuan.type = 'danxuan';
+				iDanxuan.marked = false;
+				iDanxuan.onlyNum = uIndex + 1;
+				iDanxuan.order = order;
+				iDanxuan.iQa = iQa;
+				iDanxuan.reply = iDanxuan.result;
+				paragraph.qas.push(iDanxuan);
+				uIndex++;
+				order++;
+				iQa++;
+
+				data.StListForSearch.push({
+					stId: iDanxuan.stId,
+					paragraphName: paragraph.name,
+					dlIndex: iDuanluo,
+					dtIndex: iDanxuan.iQa,
+					num: iDanxuan.onlyNum
+				})
+			}
+			order = 0;
+			for (const iDuoxuan of duanluo.duoxuan) {
+				iDuoxuan.type = 'duoxuan';
+				iDuoxuan.marked = false;
+				iDuoxuan.onlyNum = uIndex + 1;
+				iDuoxuan.order = order;
+				paragraph.qas.push(iDuoxuan);
+				iDuoxuan.reply = iDuoxuan.result;
+				iDuoxuan.iQa = iQa;
+				uIndex++;
+				order++;
+				iQa++;
+
+				data.StListForSearch.push({
+					stId: iDuoxuan.stId,
+					paragraphName: paragraph.name,
+					dlIndex: iDuanluo,
+					dtIndex: iDuoxuan.iQa,
+					num: iDuoxuan.onlyNum
+				})
+			}
+			order = 0;
+			for (const iPanduan of duanluo.panduan) {
+				iPanduan.type = 'panduan';
+				iPanduan.marked = false;
+				iPanduan.onlyNum = uIndex + 1;
+				iPanduan.order = order;
+				paragraph.qas.push(iPanduan);
+				iPanduan.reply = iPanduan.result;
+				iPanduan.iQa = iQa;
+				uIndex++;
+				order++;
+				iQa++;
+
+				data.StListForSearch.push({
+					stId: iPanduan.stId,
+					paragraphName: paragraph.name,
+					dlIndex: iDuanluo,
+					dtIndex: iPanduan.iQa,
+					num: iPanduan.onlyNum
+				})
+			}
+			order = 0;
+			for (const iTiankong of duanluo.tiankong) {
+				iTiankong.type = 'tiankong';
+				iTiankong.marked = false;
+				iTiankong.onlyNum = uIndex + 1;
+				iTiankong.order = order;
+				paragraph.qas.push(iTiankong);
+				iTiankong.reply = iTiankong.result.map(item => item[0]);
+				iTiankong.iQa = iQa;
+				uIndex++;
+				order++;
+				iQa++;
+
+				data.StListForSearch.push({
+					stId: iTiankong.stId,
+					paragraphName: paragraph.name,
+					dlIndex: iDuanluo,
+					dtIndex: iTiankong.iQa,
+					num: iTiankong.onlyNum
+				})
+			}
+			iDuanluo++;
+			questionData.value.push(paragraph)
+
+			console.log(questionData.value)
+		}
+	}
+	
+	function handleBiaoji() {
+		activeSt.value.marked = !activeSt.value.marked;
+	}
+	
+	function handleCheckJiexi() {
+		const qa = activeSt.value ;
+		let score = qa.score;
+		let reply = '';
+		let result = '';
+		let answer = qa.answer;
+		if (qa.stTypeId == 1) {
+			// 单选题
+			if (qa.reply && qa.reply.trim() !== '') {
+				reply = getLetterByIndex(qa.reply)
+			} else {
+				reply = '未答'
+			}
+			
+			if (qa.result) {
+				result = getLetterByIndex(qa.result)
+			} else {
+				result = '无答案'
+			}
+		}
+		if (qa.stTypeId == 2) {
+			// 多选题
+			
+			if (qa.reply && qa.reply.length) {
+				reply = qa.reply.map(item => {
+					if (item.trim()) {
+						return getLetterByIndex(item.trim())
+					}
+				}).join(',')
+			} else {
+				reply = '未答'
+			}
+			if (qa.result) {
+				result = qa.result.map(item => {
+					if (item.trim()) {
+						return getLetterByIndex(item.trim())
+					}
+				}).join(',')
+			} else {
+				result = '无答案'
+			}
+		}
+		if (qa.stTypeId == 3) {
+			// 判断题
+			if (qa.reply == 0) {
+				reply = '错误'
+			}else if (qa.reply == 1) {
+				reply = '正确'
+			}
+			if (qa.result == 0) {
+				result = '错误'
+			}else if (qa.result == 1) {
+				result = '正确'
+			}
+		}
+		if (qa.stTypeId == 4) {
+			let reply = qa.reply || [];
+			let result =qa.result || [];
+			// 填空题
+			scoreAnswerTkRef.value.showPopup({score,reply,result,answer})
+		} else {
+			scoreAnswerRef.value.showPopup({
+				score,reply,result,answer
+			})
+		}
+	}
+
+	function initKaoshi() {
+		lxApi.getLianxiInfo({
+			lxId: data.lxId
+		}).then(res => {
+			const {
+				lxId,
+				lxName,
+				stTotal,
+				stScore,
+				biaoji,
+				endSecond,
+				pageSize,
+				toggleScreenFlag,
+				toggleScreenSecond,
+				zhuapai,
+				duanluoList
+			} = res.data;
+			data.lxId = lxId;
+			data.lxName = lxName;
+			data.stTotal = stTotal;
+			data.stScore = stScore;
+			data.biaoji = biaoji;
+			data.endSecond = endSecond;
+			data.pageSize = pageSize;
+			data.toggleScreenFlag = toggleScreenFlag;
+			data.toggleScreenSecond = toggleScreenSecond;
+			data.zhuapai = zhuapai;
+			data.duanluo = duanluoList;
+			formatDuanluoList(data.duanluo);
+			uni.setNavigationBarTitle({
+				title: data.lxName
+			});
+			startCountDown.value = true;
+		})
+	}
+</script>

+ 13 - 7
pages/admin/Lianxi/list.vue

@@ -30,9 +30,6 @@
 								<view class="ks-totalTm">
 									<icon class="phone-time-icon" />时间:{{item.totalTm}}分钟
 								</view>
-								<view class="ks-totalTm">
-									<icon class="phone-cishu-icon" />次数:{{item.maxTimes}}次
-								</view>
 								<!-- 分数 -->
 								<view class="ks-score-content">
 									<view class="ks-score">
@@ -55,13 +52,14 @@
 		<!-- 页面底端 -->
 		<customTabbarAdminVue></customTabbarAdminVue>
 		<!-- 考试须知 -->
-		<!-- <kaoshixuzhiVue ref="ksxzRef" @confirm="handleConfirmKs"></kaoshixuzhiVue> -->
+		<lianxixuzhi ref="lxxzRef" @confirm="handleConfirmKs"></lianxixuzhi>
 	</view>
 </template>
 
 <script setup>
 	import * as lianxiApi from "@/api/lianxi.js";
 	import customTabbarAdminVue from "@/components/custom-tabbar/custom-tabbar-admin.vue";
+	import lianxixuzhi from "@/components/kaoshixuzhi/lianxixuzhi.vue";
 	import {
 		ref,
 		reactive
@@ -70,7 +68,7 @@
 		onLoad
 	} from "@dcloudio/uni-app";
 	
-	const ksxzRef = ref(null);
+	const lxxzRef = ref(null);
 	
 	const data = reactive({
 		zyName: '', // 职业名称
@@ -86,6 +84,14 @@
 		}
 	})
 	
+	function checkKsXz(data) {
+		lxxzRef.value.showDialog(data)
+	}
+	
+	function handleConfirmKs(lxId) {
+		checkKaoshi({lxId})
+	}
+	
 	function goUpPage() {
 		uni.redirectTo({
 			url: '/pages/admin/ShouYe/shouye'
@@ -98,8 +104,8 @@
 	}
 	
 	function checkKaoshi(item) {
-		uni.navigateTo({
-			url: `/pages/admin/Lianxi/info?lxId=${item.lxId}`
+		uni.redirectTo({
+			url: `/pages/admin/Lianxi/lianxi?lxId=${item.lxId}`
 		})
 	}
 	

+ 1 - 0
utils/auth.js

@@ -11,3 +11,4 @@ export function setAuth(token) {
 export function removeAuth() {
   return uni.removeStorageSync(TokenKey)
 }
+

+ 4 - 1
utils/common.js

@@ -69,4 +69,7 @@ export function debounce(func, wait) {
 
 export  function formatDuration(duration = 0) {
       return Math.round(duration / 60);
-    }
+    }
+	
+	
+	

+ 135 - 0
utils/kechengCache.js

@@ -0,0 +1,135 @@
+import cacheManager from "@/utils/cacheManager.js"
+
+const TokenKey = 'Mta-Kecheng'
+
+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;
+		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 (!pageCache || !pageCache[userId] || !pageCache[userId][pageId]) {
+			return null;
+		}
+		return pageCache[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
+	}
+}