wangxy hai 6 meses
pai
achega
c17cb5706a

+ 12 - 0
api/baoming.js

@@ -0,0 +1,12 @@
+import request from '@/utils/request'
+export function getBaomingList(data = {}) {
+	return request({
+		'url': '/app/kaoshi/signup/list',
+		headers: {
+			isToken: true
+		},
+		method: 'post',
+		data,
+		timeout: 20000
+	})
+}

+ 24 - 0
api/cuoti.js

@@ -0,0 +1,24 @@
+import request from '@/utils/request'
+export function getCuotiList(data = {}) {
+	return request({
+		'url': '/app/cuoti/list',
+		headers: {
+			isToken: true
+		},
+		method: 'post',
+		data,
+		timeout: 20000
+	})
+}
+
+export function getCuotiInfo(data = {}) {
+	return request({
+		'url': '/app/cuoti/info',
+		headers: {
+			isToken: true
+		},
+		method: 'post',
+		data,
+		timeout: 20000
+	})
+}

+ 24 - 0
api/lianxi.js

@@ -0,0 +1,24 @@
+import request from '@/utils/request'
+export function getLianxiList(data = {}) {
+	return request({
+		'url': '/app/lianxi/list',
+		headers: {
+			isToken: true
+		},
+		method: 'post',
+		data,
+		timeout: 20000
+	})
+}
+
+export function getLianxiInfo(data = {}) {
+	return request({
+		'url': '/app/lianxi/start',
+		headers: {
+			isToken: true
+		},
+		method: 'post',
+		data,
+		timeout: 20000
+	})
+}

+ 238 - 0
components/custom-scroll-list/custom-scroll-list-date.vue

@@ -0,0 +1,238 @@
+<template>
+	<view>
+		<!-- 查询区域 -->
+		<view>
+			<uni-search-bar class="uni-mt-10" v-model="name" radius="100" v-if="hasSearcBar" :placeholder="placeholder"
+				:bgColor="searchBarColor" clearButton="auto" cancelButton="none" @confirm="onSearch" @blur="onSearch" />
+			<view @click="selectDate">日历</view>
+		</view>
+
+		<!-- tab选择区域 -->
+		<view class="lli-status-box" v-if="hasTab">
+			<text :class="['status-item', activeTab === item.value? 'click':'' ]" v-for="item in tabList"
+				:key="item.value" @click="onTavChange(item)">{{item.label}}</text>
+		</view>
+		<!-- 无限滚动区域 -->
+		<scroll-view class="scroll-container" :scroll-y="true" :refresher-enabled="true"
+			:refresher-triggered="triggered" :refresher-threshold="100" refresher-background="#F3F3F4"
+			@refresherrefresh="onRefresh" @scrolltolower="onReachBottom" @refresherrestore="onRestore">
+			<slot :list="list"></slot>
+			<uni-load-more :status="status" :contentText="contentText"></uni-load-more>
+		</scroll-view>
+		<dateSelectDlVue ref="dateSelectRef" @confirm-btn="onDateSelect" @date-reset="onDateReset"></dateSelectDlVue>
+	</view>
+
+</template>
+
+<script setup>
+	import dateSelectDlVue from "@/components/dialog/dateSelectDl.vue";
+	import {
+		ref,
+		onMounted,
+		computed,
+		reactive,
+	} from "vue";
+
+	import {
+		onLoad
+	} from "@dcloudio/uni-app"
+
+
+	const props = defineProps({
+		refreshFn: {
+			type: Function,
+			required: true
+		},
+		tabData: {
+			type: Object
+		},
+		size: {
+			type: Number,
+			default: 5
+		},
+		hasSearcBar: {
+			type: Boolean,
+			default: true,
+		},
+		searchBarKey: {
+			type: String,
+			default: 'name'
+		},
+		hasTab: {
+			type: Boolean,
+			default: true,
+		},
+		defaultTab: {
+			type: [String, Number]
+		},
+		tabList: {
+			type: Array,
+			default: () => [],
+		},
+		tabKey: {
+			type: String,
+			default: 'status'
+		},
+		placeholder: {
+			type: String,
+			default: '请输入考试名称'
+		},
+		searchBarColor: {
+			type: String,
+			default: "#F3F3F4"
+		},
+		tabData: {
+			type: Object,
+		}
+
+	})
+
+	const page = ref(1);
+	const list = ref([]); // 项目列表
+	const triggered = ref(false); // 是否触发下拉刷新
+	const freshing = ref(false); // 是否加载中
+	const total = ref(0); // 项目总数
+	const name = ref(''); // 查询名
+	const activeTab = ref(props.defaultTab);
+	const status = ref('more');
+	const contentText = {
+		contentdown: '查看更多',
+		contentrefresh: '加载中',
+		contentnomore: '没有更多'
+	}
+	const dateSelectRef = ref(null);
+	const selectDateData = ref([]);
+
+	/**
+	 * 是否已完全加载
+	 */
+	const isComplete = computed(() => {
+		if (total.value === 0) {
+			return false;
+		}
+
+		return total.value === list.value.length
+	})
+
+	function onDateReset() {
+		selectDateData.value = [];
+		reset();
+		getData("do-search");
+	}
+
+	function onDateSelect(data) {
+		selectDateData.value = data;
+		reset();
+		getData("do-search");
+	}
+
+	function selectDate() {
+		console.log('open')
+		dateSelectRef.value.handleShow(selectDateData.value)
+	}
+
+	// 重置
+	function reset() {
+		list.value = [];
+		page.value = 1;
+		triggered.value = false;
+		freshing.value = false;
+		total.value = 0;
+		status.value = 'more';
+	}
+
+	// 切换tab
+	function onTavChange(item) {
+		activeTab.value = item.value;
+		name.value = "";
+		reset();
+		getData("do-search");
+	}
+
+	// 查询
+	function onSearch({
+		value
+	}) {
+		name.value = value;
+		reset();
+		getData("do-search");
+	}
+
+	// 获取数据
+	function getData(action) {
+		const options = Object.assign({}, {
+			page: page.value,
+			size: props.size,
+			answerStartTime: selectDateData.value.length ? selectDateData.value[0] : null,
+			answerEndTime: selectDateData.value.length ? selectDateData.value[1] : null,
+			passFlag: -1
+		});
+
+		if (props.hasTab) {
+			options[props.tabKey] = activeTab.value;
+		}
+
+		if (props.hasSearcBar) {
+			options[props.searchBarKey] = name.value;
+		}
+		props.refreshFn(options).then(res => {
+			total.value = res.data.total;
+			action === "do-search" && (list.value = res.data.data); // 查询更新
+			action === "pull-down-refresh" && (list.value = res.data.data); // 下拉更新数据
+			action === "reach-buttom" && (list.value = [...list.value, ...res.data.data]); // 无限滚动更新数据
+
+
+
+		}).finally(() => {
+			triggered.value = false;
+			freshing.value = false;
+			if (total.value !== list.value.length) {
+				status.value = 'more';
+			} else {
+				status.value = 'noMore';
+			}
+		})
+	}
+
+	onLoad(() => {
+		freshing.value = false;
+		setTimeout(() => {
+			triggered.value = true
+		}, 50)
+	})
+
+	// 下拉刷新触发
+	function onRefresh() {
+		if (freshing.value) return;
+		status.value = 'loading';
+		freshing.value = true;
+		triggered.value = true;
+		page.value = 1;
+		getData('pull-down-refresh');
+	}
+
+	// 下拉刷新复位
+	function onRestore() {
+		triggered.value = 'restore'; // 需要重置
+	}
+
+	// 无限滚动
+	function onReachBottom() {
+		if (freshing.value) return;
+		if (isComplete.value) return;
+		freshing.value = true;
+		page.value++;
+		getData('reach-buttom')
+	}
+
+
+	defineExpose({
+		onRefresh
+	})
+</script>
+
+<style lang="scss">
+	.scroll-container {
+		height: calc(100vh - 220rpx)
+	}
+</style>

+ 121 - 0
components/dialog/dateSelectDl.vue

@@ -0,0 +1,121 @@
+<template>
+	<uni-popup ref="commonPopup" :animation="false" :is-mask-click="false"
+	 mask-background-color="rgba(0, 0, 0, 0.4)">
+	 <view class="phone-common-dialog">
+		<view class="common-body-box">
+			<view class="common-title">请选择日期</view>
+			<view class="common-content" :class="dialogContentClass">
+				<uni-datetime-picker v-model="infoDate.selected" type="daterange" @change="dateConfirm" />
+			</view>
+			<view class="common-btn-box">
+				<view class="confirm-btn" @click="confirmBtn">确认</view>
+			</view>
+		</view>
+	 </view>
+	</uni-popup>
+</template>
+
+<script setup>
+	import { ref,reactive } from 'vue';
+	const props = defineProps({
+	  title: {
+	    type: String,
+	    default: ''
+	  },
+	  content: {
+	    type: String,
+		require: true,
+	    default: ''
+	  },
+	  dialogContentClass: {
+	    type: String,
+	  	require: true,
+	    default: 'content-center-class'
+	  },
+	  notBtn: {
+	    type: String,
+	  	require: true,
+	    default: '取消'
+	  },
+	  okBtn: {
+	    type: String,
+	  	require: true,
+	    default: '确认'
+	  },
+	});
+	const commonPopup = ref(null); // 索引
+	const $emit = defineEmits(['confirm-btn', 'date-reset'])
+	
+	/**
+	 * 获取任意时间
+	 */
+	function getDate(date, AddDayCount = 0) {
+		if (!date) {
+			date = new Date()
+		}
+		if (typeof date !== 'object') {
+			date = date.replace(/-/g, '/')
+		}
+		const dd = new Date(date)
+	
+		dd.setDate(dd.getDate() + AddDayCount) // 获取AddDayCount天后的日期
+	
+		const y = dd.getFullYear()
+		const m = dd.getMonth() + 1 < 10 ? '0' + (dd.getMonth() + 1) : dd.getMonth() + 1 // 获取当前月份的日期,不足10补0
+		const d = dd.getDate() < 10 ? '0' + dd.getDate() : dd.getDate() // 获取当前几号,不足10补0
+		return {
+			fullDate: y + '-' + m + '-' + d,
+			year: y,
+			month: m,
+			date: d,
+			day: dd.getDay()
+		}
+	}
+	const infoDate = reactive({
+		lunar: true,
+		range: true,
+		insert: false,
+		selected: [],
+		valueData: null
+	})
+	
+	function dateConfirm(data) {
+		infoDate.selected = data;
+	}
+	
+	// 打开弹窗
+	function handleShow(data) {
+		if (data) {
+			infoDate.selected = data;
+		}
+		commonPopup.value.open();
+	}
+	// 取消
+	function handleClose() {
+		commonPopup.value.close();
+	}
+	// 确认
+	function confirmBtn(){
+		if (!infoDate.selected.lenth||infoDate.selected.length>1) {
+			$emit('confirm-btn',infoDate.selected);
+			commonPopup.value.close();
+		} else {
+			uni.showToast({
+				title: '请选择日期',
+				icon: 'none'
+			})
+		}
+	}
+	function handleReset() {
+		$emit('date-reset')
+		infoDate.selected = []
+		handleClose();
+	}
+	defineExpose({
+			handleShow,
+			handleClose
+		})
+</script>
+
+<style>
+</style>

+ 0 - 1
components/kaoshixuzhi/examCountDown.vue

@@ -59,7 +59,6 @@
 
 	// 执行组件 组件启动
 	function init() {
-		console.log('init')
 		data.curCount = props.count;
 		if (data.curCount > 0) {
 			countDown(data.curCount);

+ 11 - 9
components/kaoshixuzhi/kaoshixuzhi.vue

@@ -9,7 +9,7 @@
 						class="cur-exam-count-down" @time-end="onTimeEnd"></examCountDownVue>
 				</view>
 				<view v-if="data.name">考试名称:{{data.name}}</view>
-				<view v-if="data.ksScore">用户名:{{data.ksScore}}</view>
+				<view v-if="data.userName">用户名:{{data.userName}}</view>
 				<view v-if="data.credit">学分:{{data.credit}}</view>
 				<view v-if="data.okScore">及格分:{{data.okScore}}</view>
 				<view v-if="data.ksScore">总分:{{data.ksScore}}</view>
@@ -30,11 +30,12 @@
 </template>
 
 <script setup>
-	import examCountDownVue from "./examCountDown.vue";
+	import { getAuth } from "@/utils/auth";
+import examCountDownVue from "./examCountDown.vue";
 	import {
 		ref,
 		reactive,
-		nextTick
+		nextTick,
 	} from "vue";
 	const popupRef = ref(null)
 	const countDownRef = ref(null)
@@ -64,6 +65,7 @@
 		data.endTime = options.endTime;
 		data.startSecond = options.startSecond;
 		data.ksId = options.ksId;
+		data.userName = getAuth() && getAuth().userName
 
 
 		if (typeof options.intro == 'undefined' || options.intro == null || options.intro == '') {
@@ -72,22 +74,22 @@
 			data.textareaHtml = options.intro;
 		}
 
-
-		if (options.startSecond < 0) {
+		if (data.startSecond <= 0) {
 			isCanJoinExam.value = true;
+		} else {
+			setTimeout(() => {
+				countDownRef.value.init()
+			}, 0)
 		}
 
 		popupRef.value.open('center')
-		setTimeout(() => {
-			countDownRef.value.init()
-		}, 0)
+
 	}
 
 	function handleClose() {
 		emits('cancel');
 		popupRef.value.close()
 		isCanJoinExam.value = false;
-		countDownRef.value.termination()
 	}
 
 	function handleConfirm() {

+ 42 - 1
components/questions/useQuestionTools.js

@@ -74,12 +74,53 @@ export function useQuestionTools() {
 		}
 	}
 
+	function checkJiandaReply(item) {
+		if (!item.reply || item.reply === '' || item.reply === [] || item.reply.length === 0) {
+			return false;
+		} else {
+			return true;
+		}
+	}
+
+	function checkYueduReply(qa) {
+		console.log('qa =>',qa)
+		for (const iDanxuan of qa.danxuan) {
+			if (!checkDanxuanReply(iDanxuan)) {
+				return false;
+			}
+		}
+		for (const iDuoxuan of qa.duoxuan) {
+			if (!checkDuoxuanReply(iDuoxuan)) {
+				return false;
+			}
+		}
+		for (const iPanduan of qa.panduan) {
+			if (!checkPanduanReply(iPanduan)) {
+				return false;
+			}
+		}
+		for (const iTiankong of qa.tiankong) {
+			if (!checkTiankongReply(iTiankong)) {
+				return false;
+			}
+		}
+		for (const iJianda of qa.jianda) {
+			if (!checkJiandaReply(iJianda)) {
+				return false;
+			}
+		}
+
+		return true;
+	}
+
 	return {
 		getLetterByIndex,
 		haveSameElements,
 		checkDanxuanReply,
 		checkDuoxuanReply,
 		checkPanduanReply,
-		checkTiankongReply
+		checkTiankongReply,
+		checkJiandaReply,
+		checkYueduReply
 	}
 }

+ 4 - 2
components/questions/yuedu.vue

@@ -9,7 +9,6 @@
 		<view class="yuedu-option-box">
 			<swiper class="swiper-box" @change="onSwitchChange" :current="swiperDotIndex">
 				<swiper-item v-for="(item,index) in data.content" :key="index" class="swiper-item-content">
-												{{item}}
 					<view class="swiper-item" :class="'swiper-item' + index" style="background-color: #ccc;">
 						<template v-if="item.stTypeId == 1">
 							<!-- 单选 -->
@@ -62,6 +61,7 @@
 	const data = reactive({
 		content: []
 	})
+	const Emits = defineEmits(['yudu-change'])
 
 	const swiperDotIndex = ref(0);
 
@@ -73,12 +73,14 @@
 			item.onlyNum = index+1;
 			return item
 		})
+		Emits('yudu-change', data.content[0])
 	}, {
 		immediate: true
 	})
 
 	function onSwitchChange(e) {
-		console.log('eeee', e)
+		console.log('eeee', e.detail,data.content[e.detail.current])
+		Emits('yudu-change', data.content[e.detail.current])
 	}
 </script>
 

+ 57 - 0
components/score-lianxi-card-lianxi/score-lianxi-card-lianxi.vue

@@ -0,0 +1,57 @@
+<template>
+	<view class="scroll-list-card mobile-card-box">
+		<!--   title     -->
+		<text class="mobile-card-title">{{ data.lxName === null ? "" : data.lxName }}</text>
+		<!--   content   -->
+		<view class="mobile-card-row" style="font-size: 28rpx">
+			时间:{{ data.lxStartTime === null ? "" : data.lxStartTime }}-{{
+        data.lxEndTime === null ? "" : data.lxEndTime
+      }}
+		</view>
+		<!--    button    -->
+		<template v-for="item in btns">
+			<button class="lli-btn" :key="item.index" v-if="data.status == item.status" @click="btnClick(data)">
+				{{ item.text }}
+			</button>
+		</template>
+	</view>
+</template>
+
+<script setup>
+	import {
+		toRefs,
+		ref,
+		computed
+	} from "vue";
+
+	const props = defineProps({
+		data: {
+			type: Object,
+		},
+	});
+	const {
+		data
+	} = toRefs(props);
+
+	const btns = computed(() => [{
+			index: 0,
+			status: 1,
+			text: "开始练习",
+		},
+		{
+			index: 1,
+			status: 2,
+			text: "已结束",
+		},
+	]);
+
+	const Emits = defineEmits(['btnClick'])
+
+	function btnClick(data) {
+		Emits('btnClick', data)
+	}
+</script>
+
+<style>
+
+</style>

+ 175 - 0
components/score-list-card-baoming/score-list-card-baoming.vue

@@ -0,0 +1,175 @@
+<template>
+  <view class="scroll-list-card mobile-card-box">
+    <!--   title     -->
+    <text class="mobile-card-title">{{
+      data.ksName === null ? "" : data.ksName
+    }}</text>
+    <!--   content   -->
+    <view class="mobile-card-row" style="font-size: 28rpx">
+      时间:{{ data.ksStartTime === null ? "" : data.ksStartTime }}-{{
+        data.ksEndTime === null ? "" : data.ksEndTime
+      }}
+    </view>
+    <view class="mobile-card-row">
+      <text>总分:{{ data.ksScore === null ? "" : data.ksScore }}</text>
+      <text class="card-score-box"
+        >学分:{{ data.credit === null ? "" : data.credit }}</text
+      >
+    </view>
+    <view class="mobile-card-row">
+      <text>及格分:{{ data.okScore === null ? "" : data.okScore }}</text>
+      <text class="card-score-box"
+        >考试时长:{{ data.totalTm === null ? "" : data.totalTm }}分钟</text
+      >
+    </view>
+    <!--    button    -->
+    <template v-for="item in btns" :key="item.status">
+      <button
+        class="lli-btn"
+        @click="btnClick(data)"
+        v-if="item.show"
+        :key="item.status"
+        :disabled="data.disabled"
+      >
+        {{ item.text }}
+      </button>
+    </template>
+  </view>
+</template>
+
+<script setup>
+import { toRefs, ref, computed } from "vue";
+
+const props = defineProps({
+  data: {
+    type: Object,
+  },
+});
+const { data } = toRefs(props);
+
+const btns = computed(() => [
+  {
+    status: 0,
+    btnType: "kaoshi",
+    text: "未开始",
+    show: data.value.status === 0,
+  },
+  {
+    status: 1,
+    btnType: "kaoshi",
+    text: "开始考试",
+    show: data.value.status === 1,
+  },
+  {
+    status: 3,
+    btnType: "kaoshi",
+    text: "考试中",
+    show: data.value.status === 3,
+  },
+  {
+    status: 2,
+    btnType: "kaoshi",
+    text: "再次考试",
+    show: data.value.status === 2,
+  },
+  {
+    status: 4,
+    btnType: "kaoshi",
+    text: "已结束",
+    show: data.value.status === 4,
+  },
+  {
+    status: 5,
+    btnType: "kaoshi",
+    text: "报名",
+    show: data.value.status === 5,
+  },
+  {
+    status: 6,
+    btnType: "kaoshi",
+    text: "报名审核中",
+    show: data.value.status === 6,
+  },
+  {
+    status: 7,
+    btnType: "kaoshi",
+    text: "审核未通过",
+    show: data.value.status === 7,
+  },
+  {
+    status: 8,
+    btnType: "kaoshi",
+    text: "等待人工评分",
+    show: data.value.status === 8,
+  },
+]);
+
+const Emits = defineEmits(['btnClick'])
+
+function btnClick(data) {
+	Emits('btnClick',data)
+}
+</script>
+
+<style lang="scss" scoped>
+.mobile-card-box {
+  box-sizing: border-box;
+  margin: 0 30rpx 10rpx;
+  border-bottom: 2rpx solid #f2f1f2;
+  padding-bottom: 30rpx;
+}
+
+.mobile-card-title {
+  color: #333;
+  font-size: 32rpx;
+  font-weight: 500;
+  margin: 24rpx 0 24rpx 0;
+  text-overflow: ellipsis;
+  -o-text-overflow: ellipsis;
+  overflow: hidden;
+  word-wrap: break-word;
+  display: -webkit-box;
+  white-space: normal;
+  -webkit-box-orient: vertical;
+  text-align: justify;
+  -webkit-line-clamp: 2;
+  line-clamp: 2;
+  line-height: 48rpx;
+}
+
+// 行
+.mobile-card-row {
+  margin-bottom: 32rpx;
+  display: flex;
+  justify-content: space-between;
+  align-items: flex-end;
+
+  text {
+    font-size: 28rpx;
+    line-height: 40rpx;
+  }
+
+  // 得分
+  .mobile-card-score {
+    font-size: 40rpx;
+    color: #f10a0a;
+  }
+
+  // 分数(有最小宽度)
+  .card-score-box {
+    min-width: 240rpx;
+    text-align: left;
+  }
+}
+
+// 按钮
+.mobile-card-btn {
+  width: 60%;
+  height: 80rpx;
+  line-height: 80rpx;
+  margin: 50rpx auto;
+  background: linear-gradient(0deg, #436aff 0%, #234ff7 100%);
+  border-radius: 80rpx;
+  display: block;
+}
+</style>

+ 33 - 0
components/score-list-card-cuoti/score-list-card-cuoti.vue

@@ -0,0 +1,33 @@
+<template>
+	<!--   title    -->
+	<view>{{data.ksName === null ? '': data.ksName}}</view>
+	<!--    main    -->
+	<view>总数:{{data.errorCount === null ? 0:data.errorCount}}</view>
+	<view>时间:
+		{{data.answerStartTime === null ? '' : data.answerStartTime}}
+		-
+		{{data.answerEndTime === null ? '' : data.answerEndTime}}
+	</view>
+	<!--   button   -->
+	<button :disabled="data.seeAnswerFlag === 0" @click="btnClick">
+		查看答案
+	</button>
+</template>
+
+<script setup>
+	const props = defineProps({
+		data: {
+			type: Object,
+			require: true
+		}
+	})
+	const emits = defineEmits(['btn-click'])
+
+	function btnClick() {
+		emits('btn-click', props.data);
+	}
+</script>
+
+<style>
+
+</style>

+ 40 - 0
components/scoreAndAnswer/scoreAndAnswerAdmin.vue

@@ -0,0 +1,40 @@
+<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">正确答案:<text>{{data.result}}</text></view>
+			<view class="ndda-row">您的答案:<text>{{data.reply}}</text></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>

+ 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>

+ 44 - 0
components/scoreAndAnswer/scoreAndAnswerJianda.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>{{data.result}}</view>
+			</view>
+			<view class="ndda-row">您的答案:
+			<view >{{data.reply}}</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
components/zhuapaiConfirm/answerQueren.vue

@@ -7,7 +7,7 @@
 				title="提示"
 				:duration="2000" 
 				:before-close="true"
-				:showClose="false"
+				:showClose="true"
 				@close="handleClose"
 				@confirm="handleConfirm">
 				<text>

+ 138 - 0
components/zhuapaiConfirm/qieping - 副本.vue

@@ -0,0 +1,138 @@
+<template>
+	<view></view>
+</template>
+
+<script setup>
+	import {
+		ref,
+		onUnmounted,
+		nextTick,
+		computed
+	} from "vue";
+	import {
+		getClientQiepingCheat,getClientQiepingTimes
+	} from "@/api/exam.js"
+	import {
+		useZhuapaiStore
+	} from "@/store/zhuapai.js"
+
+	const zhuapaiStore = useZhuapaiStore();
+
+	const emits = defineEmits(['zhuapai', 'forceSubmit'])
+	const zhuapaiFlag = ref(false);
+	const zhuapaixiaoshi = ref(0);
+	const leaveTime = ref('');
+	const toggleScreenSecond = ref(0);
+	const toggleScreenFlag = ref(0);
+	const ksId = ref('')
+
+	function cheatingFun() {
+		// 用户离开了当前页面
+		if (document.visibilityState === 'hidden') {
+			console.log('页面不可见');
+			if (zhuapaiFlag.value) {
+				// 此时 切出后台 发生抓拍情况下 要传递固定图片
+				console.log('切出去zhuapaixiaoshi 恢复正常');
+				zhuapaixiaoshi.value = 1
+				zhuapaiStore.setStatus(1)
+			}
+			//  计时
+			leaveTime.value = new Date().getTime();
+		} else if (document.visibilityState === 'visible') {
+			console.log('切回来 恢复正常');
+			// 用户打开或回到页面
+			if (zhuapaiFlag.value) {
+				zhuapaixiaoshi.value = 0
+				zhuapaiStore.setStatus(0)
+				emits('zhuapai') // 重置抓拍
+			}
+			zhuapaixiaoshi.value = 0
+			zhuapaiStore.setStatus(0)
+			console.log('页面可见');
+			let nowTime = new Date().getTime();
+			if (Number(nowTime) - Number(leaveTime.value) > toggleScreenSecond.value + '000') {
+				let req = {
+					ksId: ksId.value,
+				};
+				getClientQiepingCheat(req).then(res => {
+					//cutScreenDialog   是否超限 true:超过限制 false:未超过限制 ,
+					if (res.code === 0 && res.data.flag) {
+						emits('forceSubmit') // 强制交卷
+					} else {
+						emits('qiepingToast', res.data.times) // 提示警告
+					}
+				});
+			}
+		}
+	}
+
+	function zhuapaiFun() {
+		if (document.visibilityState === 'hidden') {
+			console.log('页面不可见');
+			zhuapaixiaoshi.value = 1
+			zhuapaiStore.setStatus(1)
+		} else if (document.visibilityState === 'visible') {
+			zhuapaixiaoshi.value = 0
+			zhuapaiStore.setStatus(0)
+			emits('zhuapai')
+		}
+	}
+
+	function init(options) {
+		console.log('init', options)
+		toggleScreenFlag.value = options.toggleScreenFlag;
+		toggleScreenSecond.value = options.toggleScreenSecond;
+		zhuapaiFlag.value = options.zhuapaiFlag;
+		ksId.value = options.ksId;
+		// #ifdef H5
+		if (toggleScreenFlag.value !== 0) {
+			console.log("有切屏");
+			document.addEventListener('visibilitychange', cheatingFun, false);
+			cheatingNumberSearch();
+		}
+		if (zhuapaiFlag.value && toggleScreenFlag.value == 0) {
+			console.log("有抓拍 无切屏");
+			// 有抓拍 没有切屏  此方法是 解决切到后台,抓拍停留一帧的问题
+			document.addEventListener('visibilitychange', zhuapaiFun, false);
+		}
+		// #endif
+	}
+
+	function cheatingNumberSearch() {
+		let req = {
+			ksId: ksId.value,
+		};
+		getClientQiepingTimes(req).then(res => {
+			if (res.code === 0) {
+				if (res.data.times > 0 && res.data.times <= res.data.toggleScreenFlag) {
+					emits('qiepingToast', res.data.times) // 提示警告
+				} else if (res.data.times > 0 && res.data.times >= res.data.toggleScreenFlag) {
+					emits('forceSubmit') // 强制交卷
+				} 
+			}
+		});
+	}
+
+	function stopListen() {
+		if (toggleScreenFlag.value !== 0) {
+			console.log("有切屏 销毁");
+			document.removeEventListener('visibilitychange', cheatingFun, false);
+		}
+		if (zhuapaiFlag.value && toggleScreenFlag.value == 0) {
+			console.log("有抓拍 无切屏 销毁");
+			document.removeEventListener('visibilitychange', zhuapaiFun, false);
+		}
+	}
+
+	onUnmounted(() => {
+		// 组件销毁时移除监听
+		stopListen()
+	})
+
+	defineExpose({
+		init
+	})
+</script>
+
+<style>
+</style>

+ 37 - 20
components/zhuapaiConfirm/qieping.vue

@@ -15,6 +15,7 @@
 	import {
 		useZhuapaiStore
 	} from "@/store/zhuapai.js"
+	import {onHide,onShow} from "@dcloudio/uni-app"
 
 	const zhuapaiStore = useZhuapaiStore();
 
@@ -26,9 +27,9 @@
 	const toggleScreenFlag = ref(0);
 	const ksId = ref('')
 
-	function cheatingFun() {
+	function cheatingFun(code) {
 		// 用户离开了当前页面
-		if (document.visibilityState === 'hidden') {
+		if (code === 'hidden') {
 			console.log('页面不可见');
 			if (zhuapaiFlag.value) {
 				// 此时 切出后台 发生抓拍情况下 要传递固定图片
@@ -38,7 +39,7 @@
 			}
 			//  计时
 			leaveTime.value = new Date().getTime();
-		} else if (document.visibilityState === 'visible') {
+		} else if (code === 'visible') {
 			console.log('切回来 恢复正常');
 			// 用户打开或回到页面
 			if (zhuapaiFlag.value) {
@@ -66,12 +67,12 @@
 		}
 	}
 
-	function zhuapaiFun() {
-		if (document.visibilityState === 'hidden') {
+	function zhuapaiFun(code) {
+		if (code === 'hidden') {
 			console.log('页面不可见');
 			zhuapaixiaoshi.value = 1
 			zhuapaiStore.setStatus(1)
-		} else if (document.visibilityState === 'visible') {
+		} else if (code === 'visible') {
 			zhuapaixiaoshi.value = 0
 			zhuapaiStore.setStatus(0)
 			emits('zhuapai')
@@ -79,23 +80,11 @@
 	}
 
 	function init(options) {
-		console.log('init', options)
+		console.log('切屏初始化完成',options)
 		toggleScreenFlag.value = options.toggleScreenFlag;
 		toggleScreenSecond.value = options.toggleScreenSecond;
 		zhuapaiFlag.value = options.zhuapaiFlag;
 		ksId.value = options.ksId;
-		// #ifdef H5
-		if (toggleScreenFlag.value !== 0) {
-			console.log("有切屏");
-			document.addEventListener('visibilitychange', cheatingFun, false);
-			cheatingNumberSearch();
-		}
-		if (zhuapaiFlag.value && toggleScreenFlag.value == 0) {
-			console.log("有抓拍 无切屏");
-			// 有抓拍 没有切屏  此方法是 解决切到后台,抓拍停留一帧的问题
-			document.addEventListener('visibilitychange', zhuapaiFun, false);
-		}
-		// #endif
 	}
 
 	function cheatingNumberSearch() {
@@ -124,9 +113,37 @@
 		}
 	}
 
+
+	
+	onHide(() => {
+		nextTick(() => {
+			// 切出屏幕
+			if (toggleScreenFlag.value !== 0) {
+				cheatingFun('hidden');
+				cheatingNumberSearch();
+			}
+			if (zhuapaiFlag.value && toggleScreenFlag.value == 0) {
+				zhuapaiFun('hidden');
+			}
+		})
+	})
+
+	onShow(() => {
+		nextTick(() => {
+			// 切回屏幕
+			if (toggleScreenFlag.value !== 0) {
+				cheatingFun('visit');
+				cheatingNumberSearch();
+			}
+			if (zhuapaiFlag.value && toggleScreenFlag.value == 0) {
+				zhuapaiFun('visit');
+			}
+		})
+	})
+
 	onUnmounted(() => {
 		// 组件销毁时移除监听
-		stopListen()
+		// stopListen()
 	})
 
 	defineExpose({

+ 35 - 0
pages.json

@@ -81,6 +81,41 @@
 			{
 				"navigationBarTitleText" : ""
 			}
+		},
+		{
+			"path" : "pages/lianxi/index",
+			"style" : 
+			{
+				"navigationBarTitleText" : "练习"
+			}
+		},
+		{
+			"path" : "pages/lianxi/lianxi",
+			"style" : 
+			{
+				"navigationBarTitleText" : ""
+			}
+		},
+		{
+			"path" : "pages/baoming/index",
+			"style" : 
+			{
+				"navigationBarTitleText" : "报名"
+			}
+		},
+		{
+			"path" : "pages/cuoti/index",
+			"style" : 
+			{
+				"navigationBarTitleText" : "错题"
+			}
+		},
+		{
+			"path" : "pages/cuoti/cuoti",
+			"style" : 
+			{
+				"navigationBarTitleText" : "错题答案"
+			}
 		}
 	],
 	"tabBar": {

+ 118 - 0
pages/baoming/index.vue

@@ -0,0 +1,118 @@
+<template>
+	<custom-scroll-list :refreshFn="getBaomingList" :tabList="tabData" :defaultTab="0" ref="scrollRef"
+		placeholder="请输入报名考试名称">
+		<template #default="{list}">
+			<scroll-list-card-baoming v-for="(item,index) in list" :key="item.lxId" :data="item"
+				@btnClick="handleClick"></scroll-list-card-baoming>
+		</template>
+	</custom-scroll-list>
+	<!-- 考试须知 -->
+	<kaoshixuzhi ref="ksxzRef" @confirm="handleConfirm"></kaoshixuzhi>
+</template>
+
+<script setup>
+	import scrollListCardBaoming from "@/components/score-list-card-baoming/score-list-card-baoming.vue"
+	import kaoshixuzhi from "@/components/kaoshixuzhi/kaoshixuzhi.vue"
+	import {
+		getBaomingList,
+	} from "@/api/baoming.js";
+	import {
+		ref
+	} from "vue";
+
+
+	const tabData = [{
+			label: "审核中",
+			value: 0,
+		},
+		{
+			label: "已通过",
+			value: 1,
+		}, {
+			label: "未通过",
+			value: 2,
+		}, {
+			label: "未报名",
+			value: 3,
+		}, {
+			label: "已结束",
+			value: 4,
+		}
+	]
+
+
+	function goKaoshiPage(data) {
+		uni.navigateTo({
+			url: `/pages/exam/exam?ksId=${data.ksId}&zhuapai=${data.zhuapai}`
+		})
+	}
+	
+	function handleConfirm() {
+		goKaoshiPage(activeKs.value)
+	}
+
+	function showKaoshiXuzhi() {
+		const option = {
+			ksId: activeKs.value.ksId
+		}
+		getClientKaoshiInfo(option).then(res => {
+			examNoticeInfo.value = res.data;
+			// 校验抓拍
+			doCheckZhuapai()
+		})
+
+	}
+
+	function doCheckZhuapai() {
+		if (examNoticeInfo.value.zhuapai) {
+			// 存在抓拍
+		} else {
+			// 不存在抓拍
+			ksxzRef.value.showDialog(examNoticeInfo.value)
+		}
+	}
+
+	function handleClick(data) {
+		activeKs.value = data;
+		if (data.status == 0) {
+			// 未开始
+			showKaoshiXuzhi()
+		}
+		if (data.status == 1) {
+			// 可以考试
+			showKaoshiXuzhi()
+		}
+		if (data.status == 2) {
+			// 再次考试
+			showKaoshiXuzhi()
+		}
+		if (data.status == 3) {
+			// 考试中
+			showKaoshiXuzhi()
+		}
+		if (data.status == 4) {
+			// 已结束
+			uni.showToast({
+				title: '考试已结束',
+				icon: 'none'
+			})
+		}
+		if (data.status == 5) {
+			// 未报名
+			kaoShiApply({
+				ksId: data.ksId
+			}).then(res => {
+				uni.showToast({
+					title: '报名成功',
+					icon: 'none'
+				})
+				scrollRef.value.onRefresh()
+			})
+		}
+
+	}
+</script>
+
+<style lang="scss">
+
+</style>

+ 708 - 0
pages/cuoti/cuoti.vue

@@ -0,0 +1,708 @@
+<template>
+	<view class="phone-score-page">
+		<!-- 段落 -->
+		<view class="score-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>
+				<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" @yudu-change="onYueduChange"></yuedu>
+				</template>
+			</view>
+			<!-- 底部 -->
+			<view class="kaoshi-bottom-box">
+				<view class="shiti-num-box" @click="showAnswerCard">
+					<icon class="shiti-num-icon"></icon>答题卡
+					<text
+						class="active-num">{{activeSt ? activeSt.onlyNum: 0}}</text>/<text>{{data.StListForSearch.length}}</text>
+				</view>
+			</view>
+
+			<!-- 解析 -->
+			<view v-if="activeSt" class="score-answer-box">
+				<view class="phone-question-answer-box" v-if="activeSt.stTypeId == 6">
+					<template v-if="yuduItemAnswer.stTypeId == 5">
+						<!-- 阅读题中简答题 -->
+						<view class="phone-line-title">答案解析</view>
+						<view class="btdf-row">本题得分:<text>{{yuduItemAnswer.score}}</text>分</view>
+						<view class="zqda-row">正确答案:
+							<view>{{yuduItemAnswer.result}}</view>
+						</view>
+						<view class="ndda-row">您的答案:
+							<view>{{yuduItemAnswer.reply}}</view>
+						</view>
+						<view class="dajx-row">答案解析:
+							<rich-text :nodes="yuduItemAnswer.answer"></rich-text>
+						</view>
+					</template>
+					<template v-else-if="yuduItemAnswer.stTypeId == 4">
+						<view class="phone-line-title">答案解析</view>
+						<view class="btdf-row">本题得分:<text>{{yuduItemAnswer.score}}</text>分</view>
+						<view class="zqda-row">正确答案:
+							<view v-for="(item,index) in yuduItemAnswer.result">{{`填空${index+1}`}} : {{item}}</view>
+						</view>
+						<view class="ndda-row">您的答案:
+							<view v-for="(item,index) in yuduItemAnswer.reply"> {{`填空${index+1}`}}: {{item}}</view>
+						</view>
+						<view class="dajx-row">答案解析:
+							<rich-text :nodes="yuduItemAnswer.answer"></rich-text>
+						</view>
+					</template>
+					<template v-else>
+						<view class="phone-line-title">答案解析</view>
+						<view class="btdf-row">本题得分:<text>{{yuduItemAnswer.score}}</text>分</view>
+						<view class="zqda-row">正确答案:<text>{{yuduItemAnswer.result}}</text></view>
+						<view class="ndda-row">您的答案:<text>{{yuduItemAnswer.reply}}</text></view>
+						<view class="dajx-row">答案解析:
+							<rich-text :nodes="yuduItemAnswer.answer"></rich-text>
+						</view>
+					</template>
+				</view>
+				<view class="phone-question-answer-box" v-else-if="activeSt.stTypeId == 5">
+					<view class="phone-line-title">答案解析</view>
+					<view class="btdf-row">本题得分:<text>{{data.score}}</text>分</view>
+					<view class="zqda-row">正确答案:
+						<view>{{data.result}}</view>
+					</view>
+					<view class="ndda-row">您的答案:
+						<view>{{data.reply}}</view>
+					</view>
+					<view class="dajx-row">答案解析:
+						<rich-text :nodes="data.answer"></rich-text>
+					</view>
+				</view>
+				<view class="phone-question-answer-box" v-else-if="activeSt.stTypeId == 4">
+					<view class="phone-line-title">答案解析</view>
+					<view class="btdf-row">本题得分:<text>{{answerRes.score}}</text>分</view>
+					<view class="zqda-row">正确答案:
+						<view v-for="(item,index) in answerRes.result">{{`填空${index+1}`}} : {{item}}</view>
+					</view>
+					<view class="ndda-row">您的答案:
+						<view v-for="(item,index) in answerRes.reply"> {{`填空${index+1}`}}: {{item}}</view>
+					</view>
+					<view class="dajx-row">答案解析:
+						<rich-text :nodes="answerRes.answer"></rich-text>
+					</view>
+				</view>
+				<view class="phone-question-answer-box" v-else>
+					<view class="phone-line-title">答案解析</view>
+					<view class="btdf-row">本题得分:<text>{{answerRes.score}}</text>分</view>
+					<view class="zqda-row">正确答案:<text>{{answerRes.result}}</text></view>
+					<view class="ndda-row">您的答案:<text>{{answerRes.reply}}</text></view>
+					<view class="dajx-row">答案解析:
+						<rich-text :nodes="answerRes.answer"></rich-text>
+					</view>
+				</view>
+			</view>
+		</view>
+		<!-- 上下按钮 -->
+		<view v-if="activeSt" class="score-bottom-box">
+			<view @click="handleOpenCard" class="score-num-box">
+				<icon class="score-num-icon"></icon>
+				<text
+					class="active-num">{{activeSt && activeSt.onlyNum||0}}</text>/<text>{{data.StListForSearch.length}}</text>
+			</view>
+			<view>
+				<button type="default" size="mini" hover-class="none" class="phone-green-btn score-answer-btn"
+					@click="handlePrev" v-if="!isFistStId">上一题</button>
+				<button type="default" size="mini" hover-class="none" class="phone-green-btn score-answer-btn"
+					@click="handleNext" v-if="!isLastStId">下一题</button>
+				<!-- 		<button type="default" size="mini" hover-class="none" class="phone-green-btn score-answer-btn"
+					@click="handleBack" v-if="isLastStId">完成</button> -->
+			</view>
+		</view>
+		<!-- 答题卡 -->
+		<uni-popup ref="popupRef" background-color="#fff" :animation="false" :is-mask-click="false" :mask-click="false">
+			<view class="answer-card-popup">
+				<view class="icon-title-navBar-box">
+					<view @click="handlePopupBack" class="nav-bar-icon"> </view>
+					<text class="nav-bar-title">答题卡</text>
+				</view>
+				<view class="card-content-box">
+					<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>
+			</view>
+		</uni-popup>
+
+	</view>
+</template>
+
+<script setup>
+	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";
+	import yuedu from "@/components/questions/yuedu.vue";
+	import {
+		useQuestionTools
+	} from "@/components/questions/useQuestionTools.js";
+
+	import {
+		onLoad
+	} from "@dcloudio/uni-app";
+	import {
+		ref,
+		reactive,
+		computed
+	} from "vue"
+	import * as ctApi from "@/api/cuoti.js"
+	const {
+		checkDanxuanReply,
+		checkDuoxuanReply,
+		checkPanduanReply,
+		checkTiankongReply,
+		getLetterByIndex,
+		checkJiandaReply,
+		checkYueduReply
+	} = useQuestionTools();
+
+
+	const hisId = ref(null)
+	const popupRef = ref(null)
+	const yuduItemAnswer = ref(null); // 阅读小题显示答案
+	const yuduIndexQa = ref(null); // 阅读小题答案
+
+	const data = reactive({
+		ksId: null,
+		ksName: '',
+		stTotal: 0,
+		zyLevelName: '',
+		userScore: '',
+		ksScore: 0,
+		StListForSearch: [],
+		duanluo: []
+	})
+
+	const questionData = ref([]);
+	const progress = reactive({
+		dlIndex: 0,
+		dtIndex: 0
+	})
+
+	const dlName = computed(() => {
+		if (data.StListForSearch && activeSt.value) {
+			return data.StListForSearch[activeSt.value.onlyNum].paragraphName
+		} else {
+			return ''
+		}
+	})
+
+	const activeSt = computed(() => {
+		if (questionData.value.length) {
+			return questionData.value.length && questionData.value[progress.dlIndex].qas[progress.dtIndex];
+		} else {
+			return null
+		}
+	})
+
+	const answerRes = computed(() => {
+		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 === '') {
+				reply = '未答'
+			} else 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 || [];
+			// 填空题
+			return {
+				score,
+				reply,
+				result,
+				answer
+			}
+		} else if (qa.stTypeId == 5) {
+			let reply = qa.reply;
+			let result = qa.result;
+			// 简答题
+			return {
+				score,
+				reply,
+				result,
+				answer
+			}
+		} else {
+			return {
+				score,
+				reply,
+				result,
+				answer
+			}
+		}
+	})
+
+	function showAnswerCard() {
+		popupRef.value.open('top')
+	}
+
+	function onYueduChange(data) {
+		yuduIndexQa.value = data;
+		checkYueduJiexi()
+	}
+
+	// 校验阅读解析
+	function checkYueduJiexi() {
+		console.log('格式化阅读题', yuduIndexQa.value)
+		let qa = yuduIndexQa.value;
+		let score = qa.userScore;
+		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 = '无答案'
+			}
+			yuduItemAnswer.value = {
+				score,
+				reply,
+				result,
+				answer
+			}
+		}
+		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 = '无答案'
+			}
+			yuduItemAnswer.value = {
+				score,
+				reply,
+				result,
+				answer
+			}
+		}
+		if (qa.stTypeId == 3) {
+			// 判断题
+			if (qa.reply === '') {
+				reply = '未答'
+			} else if (qa.reply == 0) {
+				reply = '错误'
+			} else if (qa.reply == 1) {
+				reply = '正确'
+			}
+			if (qa.result == 0) {
+				result = '错误'
+			} else if (qa.result == 1) {
+				result = '正确'
+			}
+			yuduItemAnswer.value = {
+				score,
+				reply,
+				result,
+				answer
+			}
+		}
+		if (qa.stTypeId == 4) {
+			let reply = qa.reply || [];
+			let result = qa.result || [];
+			// 填空题
+			yuduItemAnswer.value = {
+				score,
+				reply,
+				result,
+				answer
+			}
+		}
+		if (qa.stTypeId == 5) {
+			// 简单题
+			let reply = qa.reply ? '未答' : qa.reply;
+			let result = qa.result;
+			yuduItemAnswer.value = {
+				score,
+				reply,
+				result,
+				answer
+			}
+		}
+
+	}
+
+	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((options) => {
+		hisId.value = options.hisId;
+		initPage()
+	})
+
+
+	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';
+				}
+			} else if (qa.stTypeId == 5) {
+				if (checkJiandaReply(qa)) {
+					return 'paragraph-qa-block-done';
+				} else {
+					return 'paragraph-qa-block-init';
+				}
+			} else if (qa.stTypeId == 6) {
+				if (checkYueduReply(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/Chengji/list"
+		})
+	}
+
+
+	function formatDuanluoList() {
+		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;
+				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.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.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.iQa = iQa;
+				uIndex++;
+				order++;
+				iQa++;
+
+				data.StListForSearch.push({
+					stId: iTiankong.stId,
+					paragraphName: paragraph.name,
+					dlIndex: iDuanluo,
+					dtIndex: iTiankong.iQa,
+					num: iTiankong.onlyNum
+				})
+			}
+			order = 0;
+			for (const iJianda of duanluo.jianda) {
+				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,
+					num: iJianda.onlyNum
+				})
+			}
+			order = 0;
+			for (const iYuedu of duanluo.yuedu) {
+				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,
+					num: iYuedu.onlyNum
+				})
+			}
+			iDuanluo++;
+			questionData.value.push(paragraph)
+
+		}
+	}
+
+	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 initPage() {
+		uni.setNavigationBarTitle({
+			title: '错题'
+		});
+		ctApi.getCuotiInfo({
+			hisId: hisId.value
+		}).then(res => {
+			data.duanluo = [res.data];
+			formatDuanluoList();
+		})
+	}
+
+	function handlePopupBack() {
+		popupRef.value.close()
+	}
+
+	function handleOpenCard() {
+		popupRef.value.open('top')
+	}
+</script>
+
+<style>
+
+</style>

+ 30 - 0
pages/cuoti/index.vue

@@ -0,0 +1,30 @@
+<template>
+	<custom-scroll-list-date-vue :refreshFn="getCuotiList" :defaultTab="1" ref="scrollRef" placeholder="请输入考试名称">
+		<template #default="{list}">
+			<scroll-list-card-cuoti v-for="(item,index) in list" :key="item.lxId" :data="item"
+				@btnClick="handleClick"></scroll-list-card-cuoti>
+		</template>
+	</custom-scroll-list-date-vue>
+</template>
+
+<script setup>
+	import scrollListCardCuoti from "@/components/score-list-card-cuoti/score-list-card-cuoti.vue";
+	import customScrollListDateVue from "@/components/custom-scroll-list/custom-scroll-list-date.vue";
+	import {
+		getCuotiList,
+	} from "@/api/cuoti.js";
+	import {
+		ref
+	} from "vue";
+
+	function handleClick(data) {
+		uni.navigateTo({
+			url: `/pages/cuoti/cuoti?hisId=${data.hisId}`
+		})	
+	}
+
+</script>
+
+<style lang="scss">
+
+</style>

+ 243 - 56
pages/exam/exam.vue

@@ -1,10 +1,9 @@
 <template>
 	<view class="phone-kaoshi-page">
 		<!-- 导航区域 -->
-		<view class="icon-title-bjcolor-navBar-box">
-			<view @click="handleBack" class="nav-bar-icon"></view>
+		<!-- <view class="icon-title-bjcolor-navBar-box">
 			<text class="nav-bar-title">{{data.ksName}}</text>
-		</view>
+		</view> -->
 		<!-- 第一行 -->
 		<view class="kaoshi-page-title">
 			<view v-if="activeSt" class="title-types">{{dlName}}</view>
@@ -51,8 +50,7 @@
 				@click="handleBiaoji">{{activeSt && activeSt.marked ? '取标':'标记'}}</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>
+				<text class="active-num">{{answercartsCount}}</text>/<text>{{data.StListForSearch.length}}</text>
 			</view>
 			<button class="phone-green-btn save-btn" hover-class="none" type="default" size="mini"
 				@click="handleSave(true)">保存</button>
@@ -95,15 +93,15 @@
 		</template>
 
 		<!-- 切屏 -->
-		<!-- 	<qiepingVue ref="qiepingRef" @zhuapai="qpZhuapai" @forceSubmit="forceSubmit" @qiepingToast="qiepingToast"
-			key="3"></qiepingVue> -->
+		<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> -->
+		<qiepingDlVue ref="qiepingDlRef" :content="messageContent" title="注意" okBtn="知道了"></qiepingDlVue>
 	</view>
 </template>
 
@@ -143,7 +141,9 @@
 		checkDuoxuanReply,
 		checkPanduanReply,
 		checkTiankongReply,
-		getLetterByIndex
+		getLetterByIndex,
+		checkJiandaReply,
+		checkYueduReply
 	} = useQuestionTools();
 	const {
 		saveCacheKs,
@@ -175,8 +175,8 @@
 	const subScoreRef = ref(null);
 	const messageContent = ref('');
 	const qiepingDlRef = ref(null);
-
 	const timer1 = ref(null);
+	const answercartsCount = ref(0); // 已答题数
 
 	const data = reactive({
 		ksId: null,
@@ -213,12 +213,47 @@
 		}
 	})
 
-	watch(() => data.duanluo, (newVal) => {
+	watch(() => questionData, (newVal) => {
 		// 计算已答试题数量
+		renderPage(newVal);
 	}, {
 		deep: true
 	})
 
+	function renderPage(data) {
+		let count = 0;
+		for (const paragraph of data.value) {
+			for (const qa of paragraph.qas) {
+				if (qa.stTypeId == 1) {
+					if (checkDanxuanReply(qa)) {
+						count++;
+					}
+				} else if (qa.stTypeId == 2) {
+					if (checkDuoxuanReply(qa)) {
+						count++;
+					}
+				} else if (qa.stTypeId == 3) {
+					if (checkPanduanReply(qa)) {
+						count++;
+					}
+				} else if (qa.stTypeId == 4) {
+					if (checkTiankongReply(qa)) {
+						count++;
+					}
+				} else if (qa.stTypeId == 5) {
+					if (checkJiandaReply(qa)) {
+						count++;
+					}
+				} else if (qa.stTypeId == 4) {
+					if (checkYueduReply(qa)) {
+						count++;
+					}
+				}
+			}
+		}
+		answercartsCount.value = count;
+	}
+
 	const activeSt = computed(() => {
 		if (questionData.value.length) {
 			return questionData.value.length && questionData.value[progress.dlIndex].qas[progress.dtIndex];
@@ -249,8 +284,9 @@
 
 	// 考试得分相关 start
 	function handleScoreConfirm() {
+		// 跳转成绩
 		uni.redirectTo({
-			url: `/pages/client/Chengji/ksScoreShijuan?hisId=${data.hisId}&from=kaoshi`
+			url: `/pages/client/Chengji/ksScoreShijuan?hisId=${data.hisId}`
 		})
 	}
 
@@ -272,18 +308,77 @@
 
 		const result = []
 		const option = {
-			force: false,
 			operId: data.operId,
 			replyList: []
 		}
 		questionData.value.forEach(dl => {
-			dl.qas.forEach(st => {
-				const opt = {
-					stId: st.stId,
-					reply: st.reply,
+			dl.qas.forEach(qa => {
+				console.log('qa:', qa)
+				if (qa.stTypeId == 5) {
+					const opt = {
+						stId: qa.stId,
+						files: qa.files,
+						reply: qa.reply,
+					}
+					result.push(opt)
+					option.replyList.push(opt)
+				} else if (qa.stTypeId != 6) {
+					const opt = {
+						stId: qa.stId,
+						reply: qa.reply,
+					}
+					result.push(opt)
+					option.replyList.push(opt)
+				} else {
+					// 阅读题
+					let danxuanArr = [];
+					for (const iDanxuan of qa.danxuan) {
+						danxuanArr.push(iDanxuan.reply);
+					}
+					let duoxuanArr = [];
+					for (const iDuoxuan of qa.duoxuan) {
+						duoxuanArr.push(iDuoxuan.reply);
+					}
+
+					let panduanArr = [];
+					for (const iPanduan of qa.panduan) {
+						panduanArr.push(iPanduan.reply);
+					}
+
+					let tiankongArr = [];
+					for (const iTiankong of qa.tiankong) {
+						tiankongArr.push(iTiankong.reply);
+					}
+
+					let jiandaArr = [];
+					for (const iJianda of qa.jianda) {
+						const c = {
+							files: iJianda.files,
+							reply: iJianda.reply,
+						};
+						jiandaArr.push(c);
+					}
+					result.push({
+						reply: {
+							danxuan: danxuanArr,
+							duoxuan: duoxuanArr,
+							panduan: panduanArr,
+							tiankong: tiankongArr,
+							jianda: jiandaArr,
+						},
+						stId: qa.stId,
+					})
+					option.replyList.push({
+						reply: {
+							danxuan: danxuanArr,
+							duoxuan: duoxuanArr,
+							panduan: panduanArr,
+							tiankong: tiankongArr,
+							jianda: jiandaArr,
+						},
+						stId: qa.stId,
+					});
 				}
-				result.push(opt)
-				option.replyList.push(opt)
 			})
 		})
 		// 保存试题答案
@@ -310,32 +405,29 @@
 		const result = []
 		let count = 0;
 		let total = 0;
-		questionData.value.forEach(dl => {
-			dl.qas.forEach(st => {
-				const opt = {
-					stId: st.stId,
-					reply: st.reply,
-					stTypeId: st.stTypeId
+		questionData.value.forEach(item => {
+			item.qas.forEach(qa => {
+				total++;
+				if (qa.stTypeId == 1 && !checkDanxuanReply(qa)) {
+					count++;
+				}
+				if (qa.stTypeId == 2 && !checkDuoxuanReply(qa)) {
+					count++;
+				}
+				if (qa.stTypeId == 3 && !checkPanduanReply(qa)) {
+					count++;
+				}
+				if (qa.stTypeId == 4 && !checkTiankongReply(qa)) {
+					count++;
+				}
+				if (qa.stTypeId == 5 && !checkJiandaReply(qa)) {
+					count++;
+				}
+				if (qa.stTypeId == 6 && !checkYueduReply(qa)) {
+					count++;
 				}
-				result.push(opt)
 			})
 		})
-
-		result.forEach(item => {
-			total++;
-			if (item.stTypeId == 1 && !checkDanxuanReply(item)) {
-				count++;
-			}
-			if (item.stTypeId == 2 && !checkDuoxuanReply(item)) {
-				count++;
-			}
-			if (item.stTypeId == 3 && !checkPanduanReply(item)) {
-				count++;
-			}
-			if (item.stTypeId == 4 && !checkTiankongReply(item)) {
-				count++;
-			}
-		})
 		return {
 			total,
 			count,
@@ -344,7 +436,6 @@
 
 	function handleJiaojuan() {
 		const result = checkJiaojuan()
-		console.log(result)
 		if (result.count) {
 			// 提示
 			answerQrRef.value.showDialog({
@@ -368,11 +459,64 @@
 		};
 		questionData.value.forEach(dl => {
 			dl.qas.forEach(st => {
-				const opt = {
-					stId: st.stId,
-					reply: st.reply
+				if (st.stTypeId == 5) {
+					// 简答题
+					const opt = {
+						stId: st.stId,
+						reply: st.reply,
+						files: st.files,
+					}
+					result.replyList.push(opt)
+				} else if (st.stTypeId == 6) {
+					// 阅读题
+					// 阅读题
+					let danxuanArr = [];
+					for (const iDanxuan of qa.danxuan) {
+						danxuanArr.push(iDanxuan.reply);
+					}
+					let duoxuanArr = [];
+					for (const iDuoxuan of qa.duoxuan) {
+						duoxuanArr.push(iDuoxuan.reply);
+					}
+
+					let panduanArr = [];
+					for (const iPanduan of qa.panduan) {
+						panduanArr.push(iPanduan.reply);
+					}
+
+					let tiankongArr = [];
+					for (const iTiankong of qa.tiankong) {
+						tiankongArr.push(iTiankong.reply);
+					}
+
+					let jiandaArr = [];
+					for (const iJianda of qa.jianda) {
+						const c = {
+							files: iJianda.files,
+							reply: iJianda.reply,
+						};
+						jiandaArr.push(c);
+					}
+					result.replyList.push({
+						reply: {
+							danxuan: danxuanArr,
+							duoxuan: duoxuanArr,
+							panduan: panduanArr,
+							tiankong: tiankongArr,
+							jianda: jiandaArr,
+						},
+						stId: qa.stId,
+					})
+				} else {
+					// 其他
+					const opt = {
+						stId: st.stId,
+						reply: st.reply
+					}
+					result.replyList.push(opt)
 				}
-				result.replyList.push(opt)
+
+
 			})
 		})
 
@@ -476,6 +620,18 @@
 				} else {
 					return 'paragraph-qa-block-init';
 				}
+			} else if (qa.stTypeId == 5) {
+				if (checkJiandaReply(qa)) {
+					return 'paragraph-qa-block-done';
+				} else {
+					return 'paragraph-qa-block-init';
+				}
+			} else if (qa.stTypeId == 6) {
+				if (checkYueduReply(qa)) {
+					return 'paragraph-qa-block-done';
+				} else {
+					return 'paragraph-qa-block-init';
+				}
 			}
 		}
 	}
@@ -661,12 +817,12 @@
 						return qIt
 					})
 				}
-				
+
 				if (iYuedu.tiankong && iYuedu.tiankong.length) {
 					iYuedu.tiankong.map((qIt) => {
 						qIt.reply = new Array(qIt.count).fill('');
 						return qIt;
-					}) ;
+					});
 				}
 
 
@@ -714,7 +870,34 @@
 			if (replyList) {
 				questionData.value.forEach(dl => {
 					dl.qas.forEach(st => {
-						st.reply = replyList.find(item => item.stId == st.stId).reply
+						if (st.stTypeId == 5) {
+							// 简答题
+							st.reply = replyList.find(item => item.stId == st.stId).reply;
+							st.files = replyList.find(item => item.stId == st.stId).files;
+						} else if (st.stTypeId != 6) {
+							st.reply = replyList.find(item => item.stId == st.stId).reply
+						} else {
+							// 阅读题
+							const hisSt = replyList.find(item => item.stId == st.stId);
+							if (hisSt) {
+								st.danxuan.forEach((itm, index) => {
+									itm.reply = hisSt.reply['danxuan'][index];
+								})
+								st.duoxuan.forEach((itm, index) => {
+									itm.reply = hisSt.reply['duoxuan'][index];
+								})
+								st.panduan.forEach((itm, index) => {
+									itm.reply = hisSt.reply['panduan'][index];
+								})
+								st.tiankong.forEach((itm, index) => {
+									itm.reply = hisSt.reply['tiankong'][index];
+								})
+								st.jianda.forEach((itm, index) => {
+									itm.reply = hisSt.reply['jianda'][index].reply;
+									itm.files = hisSt.reply['jianda'][index].files;
+								})
+							}
+						}
 					})
 				})
 			}
@@ -777,14 +960,18 @@
 			}
 
 			// 设置切屏监听
-			// qiepingRef.value.init({
-			// 	zhuapaiFlag: true,
-			// 	toggleScreenFlag: toggleScreenFlag,
-			// 	toggleScreenSecond: toggleScreenSecond,
-			// 	ksId: data.ksId
-			// })
+			qiepingRef.value.init({
+				zhuapaiFlag: !!zhuapai,
+				toggleScreenFlag: toggleScreenFlag,
+				toggleScreenSecond: toggleScreenSecond,
+				ksId: data.ksId
+			})
 
 			startCountDown.value = true;
+
+			uni.setNavigationBarTitle({
+				title: data.ksName
+			});
 		}).catch(err => {
 			console.log('asdasd', err)
 			// handleBack()

+ 4 - 1
pages/exam/index.vue

@@ -40,7 +40,10 @@
 	]
 
 	function goKaoshiPage(data) {
-		uni.redirectTo({
+		/* uni.redirectTo({
+			url: `/pages/exam/exam?ksId=${data.ksId}&zhuapai=${data.zhuapai}`
+		}) */
+		uni.navigateTo({
 			url: `/pages/exam/exam?ksId=${data.ksId}&zhuapai=${data.zhuapai}`
 		})
 	}

+ 97 - 6
pages/index/index.vue

@@ -39,11 +39,11 @@
 		<!-- 考试list -->
 		<view class="lli-index-title-box">
 			<text class="index-title">最热考试</text>
-			<text class="index-sub-title" @click="developClick">查看更多 ></text>
+			<text class="index-sub-title" @click="handleCheckMoreKs">查看更多 ></text>
 		</view>
 		<view class="lli-card-box">
 			<uni-card padding="0" margin="0" spacing="0" :is-shadow="false" :border="false" 
-			v-for="(item ,index) in examCardList" :index="index" :key="index" class="lli-card-item" @click="developClick(index)">
+			v-for="(item ,index) in examCardList" :index="index" :key="index" class="lli-card-item" @click="handleClickKs(item)">
 				<view class="custom-cover">
 					<image class="lli-card-image" mode="aspectFill" :src="item.pic || defultKsImg"></image>
 					<view class="cover-content" v-if="item.status">
@@ -54,10 +54,19 @@
 			</uni-card>
 		</view>
 		
+		
+		
+		<!-- 考试须知 -->
+		<kaoshixuzhi ref="ksxzRef" @confirm="handleConfirm"></kaoshixuzhi>
 	</view>
 </template>
 
 <script setup>
+	import {
+		kaoShiApply,
+		getClientKaoshiInfo
+	} from "@/api/exam.js";
+	import kaoshixuzhi from "@/components/kaoshixuzhi/kaoshixuzhi.vue"
 	import {ref,reactive} from "vue";
 	import {getCourseList, getNoticeCount,getExamList} from '@/api/index.js';
 	import {onLoad} from "@dcloudio/uni-app"
@@ -88,6 +97,9 @@
 	let courseCardList = ref([]);
 	let examCardList = ref([]);
 	let noticeCount = ref(0);
+	const examNoticeInfo = ref(null); // 考试须知数据
+	const ksxzRef = ref(null);
+	const activeKs = ref(null);
 	
 	onLoad(() => {
 		getNoticeCountData();
@@ -142,10 +154,9 @@
 			    });
 			    break;
 			case 2:
-			    uni.showToast({
-					icon: 'none',
-			    	title: '开发中,敬请期侍!',
-			    });
+			    uni.navigateTo({
+			    	url: '/pages/lianxi/index'
+			    })
 			    break;
 			case 3:
 			    uni.navigateTo({
@@ -161,6 +172,86 @@
 		});
 	}
 	
+	function goKaoshiPage(data) {
+		/* uni.redirectTo({
+			url: `/pages/exam/exam?ksId=${data.ksId}&zhuapai=${data.zhuapai}`
+		}) */
+		uni.navigateTo({
+			url: `/pages/exam/exam?ksId=${data.ksId}&zhuapai=${data.zhuapai}`
+		})
+	}
+	
+	function handleConfirm() {
+		goKaoshiPage(activeKs.value)
+	}
+	
+	function showKaoshiXuzhi() {
+		const option = {
+			ksId: activeKs.value.ksId
+		}
+		getClientKaoshiInfo(option).then(res => {
+			examNoticeInfo.value = res.data;
+			// 校验抓拍
+			doCheckZhuapai()
+		})
+	
+	}
+	
+	function doCheckZhuapai() {
+		if (examNoticeInfo.value.zhuapai) {
+			// 存在抓拍
+		} else {
+			// 不存在抓拍
+			ksxzRef.value.showDialog(examNoticeInfo.value)
+		}
+	}
+	
+	function handleClickKs(data) {
+		activeKs.value = data;
+		console.log('ddddd',data)
+		if (data.status == 0) {
+			// 未开始
+			showKaoshiXuzhi()
+		}
+		if (data.status == 1) {
+			// 可以考试
+			showKaoshiXuzhi()
+		}
+		if (data.status == 2) {
+			// 再次考试
+			showKaoshiXuzhi()
+		}
+		if (data.status == 3) {
+			// 考试中
+			showKaoshiXuzhi()
+		}
+		if (data.status == 4) {
+			// 已结束
+			uni.showToast({
+				title: '考试已结束',
+				icon: 'none'
+			})
+		}
+		if (data.status == 5) {
+			// 未报名
+			kaoShiApply({
+				ksId: data.ksId
+			}).then(res => {
+				uni.showToast({
+					title: '报名成功',
+					icon: 'none'
+				})
+				scrollRef.value.onRefresh()
+			})
+		}
+	
+	}
+	
+	function handleCheckMoreKs() {
+		uni.switchTab({
+			url: '/pages/exam/index'
+		})
+	}
 	
 </script>
 

+ 40 - 0
pages/lianxi/index.vue

@@ -0,0 +1,40 @@
+<template>
+	<custom-scroll-list :refreshFn="getLianxiList" :tabList="tabData" :defaultTab="1" ref="scrollRef"
+		placeholder="请输入练习名称">
+		<template #default="{list}">
+			<scroll-list-card-lianxi v-for="(item,index) in list" :key="item.lxId" :data="item"
+				@btnClick="handleClick"></scroll-list-card-lianxi>
+		</template>
+	</custom-scroll-list>
+</template>
+
+<script setup>
+	import scrollListCardLianxi from "@/components/score-lianxi-card-lianxi/score-lianxi-card-lianxi.vue"
+	import {
+		getLianxiList,
+	} from "@/api/lianxi.js";
+	import {
+		ref
+	} from "vue";
+
+
+	const tabData = [{
+			label: "开始练习",
+			value: 1,
+		},
+		{
+			label: "已结束",
+			value: 2,
+		}
+	]
+
+	function handleClick(data) {
+		uni.redirectTo({
+			url: `/pages/lianxi/lianxi?lxId=${data.lxId}`
+		})
+	}
+</script>
+
+<style lang="scss">
+
+</style>

+ 727 - 0
pages/lianxi/lianxi.vue

@@ -0,0 +1,727 @@
+<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">{{dlName}}</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>
+				<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" @yudu-change="onYueduChange"></yuedu>
+				</template>
+			</view>
+
+		</view>
+
+		<view class="kaoshi-bottom-box">
+			<button class="phone-green-btn bj-btn" hover-class="none" type="default" size="mini"
+				@click="handleBiaoji">{{activeSt && activeSt.marked ? '取标':'标记'}}</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" :animation="false" :is-mask-click="false" :mask-click="false">
+			<view class="answer-card-popup">
+				<view class="icon-title-navBar-box">
+					<view @click="handlePopupBack" class="nav-bar-icon"> </view>
+					<text class="nav-bar-title">答题卡</text>
+				</view>
+				<view class="card-content-box">
+					<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>
+			</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>
+		<scoreAndAnswerAdminJianda ref="scoreAnswerJdRef"></scoreAndAnswerAdminJianda>
+	</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 jianda from "@/components/questions/jianda.vue";
+	import yuedu from "@/components/questions/yuedu.vue";
+	import scoreAndAnswerVue from "@/components/scoreAndAnswer/scoreAndAnswerAdmin.vue";
+	import scoreAndAnswerAdminTiankong from "@/components/scoreAndAnswer/scoreAndAnswerAdminTiankong.vue";
+	import scoreAndAnswerAdminJianda from "@/components/scoreAndAnswer/scoreAndAnswerJianda.vue";
+	import {
+		useQuestionTools
+	} from "@/components/questions/useQuestionTools.js";
+
+	const {
+		checkDanxuanReply,
+		checkDuoxuanReply,
+		checkPanduanReply,
+		checkTiankongReply,
+		getLetterByIndex,
+		checkJiandaReply,
+		checkYueduReply
+	} = useQuestionTools();
+
+	const stTypes = {
+		1: '单选题',
+		2: '多选题',
+		3: '判断题',
+		4: '填空题',
+	}
+
+	const popupRef = ref(null)
+	const scoreAnswerRef = ref(null)
+	const scoreAnswerTkRef = ref(null)
+	const startCountDown = ref(false);
+	const scoreAnswerJdRef = ref(null);
+
+	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 yuduIndexQa = ref(null);
+
+	const questionData = ref([]);
+
+	const progress = reactive({
+		dlIndex: 0,
+		dtIndex: 0
+	})
+
+	const dlName = computed(() => {
+		if (data.StListForSearch && activeSt.value) {
+			return data.StListForSearch[activeSt.value.onlyNum - 1].paragraphName
+		} else {
+			return ''
+		}
+	})
+
+	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';
+				}
+			} else if (qa.stTypeId == 5) {
+				if (checkJiandaReply(qa)) {
+					return 'paragraph-qa-block-done';
+				} else {
+					return 'paragraph-qa-block-init';
+				}
+			} else if (qa.stTypeId == 6) {
+				if (checkYueduReply(qa)) {
+					return 'paragraph-qa-block-done';
+				} else {
+					return 'paragraph-qa-block-init';
+				}
+			}
+		}
+	}
+
+	function skipQuestion(dlIndex, dtIndex) {
+		progress.dlIndex = dlIndex;
+		progress.dtIndex = dtIndex;
+		handlePopupBack()
+		// 切换试题时清空阅读提解析
+		yuduIndexQa.value = null;
+	}
+
+	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/Lianxi/list"
+		})
+	}
+
+	function onTimeUp() {
+		console.log('end')
+	}
+
+	function showAnswerCard() {
+		popupRef.value.open('top')
+	}
+
+	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
+		}
+		// 切换试题时清空阅读提解析
+		yuduIndexQa.value = null;
+	}
+
+	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
+		}
+		// 切换试题时清空阅读提解析
+		yuduIndexQa.value = null
+	}
+
+	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
+				})
+			}
+			order = 0;
+			for (const iJianda of duanluo.jianda) {
+				iJianda.marked = 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,
+					num: iJianda.onlyNum
+				})
+			}
+			order = 0;
+			for (const iYuedu of duanluo.yuedu) {
+				iYuedu.marked = 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,
+					num: iYuedu.onlyNum
+				})
+			}
+
+			iDuanluo++;
+			questionData.value.push(paragraph)
+
+			console.log(questionData.value)
+		}
+	}
+
+	function handleBiaoji() {
+		activeSt.value.marked = !activeSt.value.marked;
+	}
+	// 切换阅读小题时更新当前试题解析
+	function onYueduChange(qa) {
+		yuduIndexQa.value = qa;
+	}
+
+	// 校验阅读解析
+	function checkYueduJiexi() {
+		let qa = yuduIndexQa.value;
+		let score = qa.userScore;
+		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 = '无答案'
+			}
+			scoreAnswerRef.value.showPopup({
+				score,
+				reply,
+				result,
+				answer
+			})
+		}
+		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 = '无答案'
+			}
+			scoreAnswerRef.value.showPopup({
+				score,
+				reply,
+				result,
+				answer
+			})
+		}
+		if (qa.stTypeId == 3) {
+			// 判断题
+			if (qa.reply === '') {
+				reply = '未答'
+			} else if (qa.reply == 0) {
+				reply = '错误'
+			} else if (qa.reply == 1) {
+				reply = '正确'
+			}
+			if (qa.result == 0) {
+				result = '错误'
+			} else if (qa.result == 1) {
+				result = '正确'
+			}
+			scoreAnswerRef.value.showPopup({
+				score,
+				reply,
+				result,
+				answer
+			})
+		}
+		if (qa.stTypeId == 4) {
+			let reply = qa.reply || [];
+			let result = qa.result || [];
+			// 填空题
+			scoreAnswerTkRef.value.showPopup({
+				score,
+				reply,
+				result,
+				answer
+			})
+		}
+		if (qa.stTypeId == 5) {
+			// 简单题
+			let reply = qa.reply ? '未答' : qa.reply;
+			let result = qa.result;
+			scoreAnswerJdRef.value.showPopup({
+				score,
+				reply,
+				result,
+				answer
+			})
+		}
+
+	}
+
+	// 获取解析
+	function handleCheckJiexi() {
+		const qa = activeSt.value;
+		let score = qa.userScore;
+		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 = '无答案'
+			}
+			scoreAnswerRef.value.showPopup({
+				score,
+				reply,
+				result,
+				answer
+			})
+		}
+		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 = '无答案'
+			}
+			scoreAnswerRef.value.showPopup({
+				score,
+				reply,
+				result,
+				answer
+			})
+		}
+		if (qa.stTypeId == 3) {
+			// 判断题
+			if (qa.reply === '') {
+				reply = '未答'
+			} else if (qa.reply == 0) {
+				reply = '错误'
+			} else if (qa.reply == 1) {
+				reply = '正确'
+			}
+			if (qa.result == 0) {
+				result = '错误'
+			} else if (qa.result == 1) {
+				result = '正确'
+			}
+			scoreAnswerRef.value.showPopup({
+				score,
+				reply,
+				result,
+				answer
+			})
+		}
+		if (qa.stTypeId == 4) {
+			let reply = qa.reply || [];
+			let result = qa.result || [];
+			// 填空题
+			scoreAnswerTkRef.value.showPopup({
+				score,
+				reply,
+				result,
+				answer
+			})
+		}
+		if (qa.stTypeId == 5) {
+			// 简单题
+			let reply = qa.reply;
+			let result = qa.result;
+			scoreAnswerJdRef.value.showPopup({
+				score,
+				reply,
+				result,
+				answer
+			})
+		}
+		if (qa.stTypeId == 6) {
+			// 简单题
+			checkYueduJiexi()
+		}
+
+	}
+
+	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);
+			startCountDown.value = true;
+			uni.setNavigationBarTitle({
+				title: data.lxName
+			});
+		})
+	}
+</script>

+ 2 - 2
pages/my/index.vue

@@ -126,14 +126,14 @@
 			// 错题
 			case 'cuoti':
 			    uni.navigateTo({
-			    	url:'/pages/admin/my/myInfo?from=my'
+			    	url:'/pages/cuoti/index'
 			    })
 			break;
 			
 			// 报名
 			case 'baoming':
 			    uni.navigateTo({
-			    	url:'/pages/admin/my/myInfo?from=my'
+			    	url:'/pages/baoming/index'
 			    })
 			break;