wangxy hai 1 mes
pai
achega
028e2afafe

+ 1 - 1
components/listCard/kaoshiCard.vue

@@ -113,7 +113,7 @@
 	
 	function checkKaoshi(item) {
 		uni.navigateTo({
-			url: `/pages/client/Kaoshi/exam?ksId=${item.ksId}&zhuapai=${activeks.value.zhuapai}&userKaozhengId=${activeks.value.userKaozhengId}&from=shouye`
+			url: `/pages/client/Kaoshi/examCamera?ksId=${item.ksId}&zhuapai=${activeks.value.zhuapai}&userKaozhengId=${activeks.value.userKaozhengId}&from=shouye`
 		})
 	}
 	

+ 13 - 39
components/zhuapaiConfirm/index.vue

@@ -1,18 +1,12 @@
 <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-camera my-dialog-cc" :title="title" :duration="2000" :before-close="true"
-			@close="handleClose" @confirm="handleConfirm">
+		<uni-popup-dialog mode="input" class="phone-camera my-dialog-cc" :title="title" :duration="2000"
+			:before-close="true" @close="handleClose" @confirm="handleConfirm">
 			<view class="phone-camera-box" style="overflow: hidden;">
 				<view v-show="!showConfirmBtn" class="sxt-tip-box" style="text-align: center;">{{textMess}}</view>
-				<video v-show="showConfirmBtn" ref="videoRef" style="width:100%; height: 320rpx;" id="videoConfirm"
-					:controls="false" :enable-progress-gesture="false"></video>
-					
-				<!-- 隐藏抓拍绘制图片 -->
-				<canvas id="canvasConfirm" style="width: auto; height: 320rpx;visibility: hidden;position: absolute;"></canvas>
-				<!-- <canvas id="canvasConfirm" style="width: auto; height: 320rpx;"></canvas> -->
-				<!-- 测试抓拍使用 -->
-				<!-- <button @click="handleZhua">抓拍</button> -->
+				<camera v-show="showConfirmBtn" class="camera" device-position="back" flash="off" @initdone="onVideoSuccess"
+					style="width:100%; height: 320rpx;"></camera>
 			</view>
 		</uni-popup-dialog>
 	</uni-popup>
@@ -28,19 +22,20 @@
 	import {
 		useH5Camera
 	} from "./useCamera.js"
-	
+
 	defineProps({
 		title: {
 			type: String,
 			default: '摄像头确认'
 		}
 	})
-	
+
 	const emits = defineEmits(['success', 'error', 'cancel'])
-	
+
 	const popupRef = ref(null)
 	const showConfirmBtn = ref(false);
-	
+	const cameraContext = ref(null);
+
 	let zhuapaiFun = null;
 	let stopCamera = null;
 	let errorFunCompleteFn = null;
@@ -48,28 +43,7 @@
 
 	function startCamera() {
 		// 请求摄像头权限并获取流
-		// #ifdef H5
-		console.log('navigator', navigator)
-		const {
-			startH5Camera,
-			handlePaiZhao,
-			stopH5Camera,
-			errorFunComplete
-		} = useH5Camera({
-			elVideoId: '#videoConfirm',
-			elCanvasId: '#canvasConfirm',
-			onVideoSuccess,
-			onVideoError
-		})
-		startH5Camera();
-		zhuapaiFun = handlePaiZhao;
-		stopCamera = stopH5Camera;
-		errorFunCompleteFn = errorFunComplete;
-		// #endif
-
-		// #ifdef APP-PLUS
-		console.log('App端暂时不支持摄像头功能')
-		// #endif
+		cameraContext.value = uni.createCameraContext();
 	}
 
 	function handleZhua() {
@@ -131,7 +105,7 @@
 		width: 100%;
 	}
 
-  .my-dialog-cc .uni-dialog-button-group .uni-border-left .uni-button-color{
-      color: #3fd2a1;
-  }
+	.my-dialog-cc .uni-dialog-button-group .uni-border-left .uni-button-color {
+		color: #3fd2a1;
+	}
 </style>

+ 111 - 61
components/zhuapaiConfirm/zhuapai.vue

@@ -2,17 +2,13 @@
 	<view class="zhuapai-drop-container" id="Drop" ref="DropRef" :style="style" @touchmove="touchmove($event)"
 		@touchstart="touchstart($event)">
 		<view class="phone-camera-box-zhuapai">
-			<video ref="videoRef" class="video-view-box" :class="myClass" id="videoZhaPai" :controls="false"></video>
-			<!-- 隐藏抓拍绘制图片 -->
-			<canvas id="canvasZhuaPai" class="video-view-box canvas-view-box" :class="myClass"></canvas>
+			<camera class="camera" device-position="back" flash="off" style="width: 200px;height: 200px" :class="myClass" @initdone="onVideoSuccess"></camera>
 			<!-- 用于抓拍切出去传递固定img-->
-			<!-- #ifdef H5 -->
-			<img :src="imgUrl" alt="" id="gdImg" v-show="false">
-			<!-- #endif -->
+			<img :src="imgUrl" alt="" v-show="false">
 			<!-- 测试抓拍使用 -->
 			<!-- <button @click="handleZhua">抓拍</button> -->
 		</view>
-		<span v-show="showVideo" @click="noShowVideoBtn" class="shiti-video-hidden-btn"><i></i></span>
+		<span v-show="showVideo" @click="noShowVideoBtn" class="shiti-video-hidden-btn"><i>隐藏</i></span>
 		<span v-show="!showVideo" @click="showVideoBtn" class="shiti-video-show-btn"><i></i></span>
 	</view>
 </template>
@@ -22,21 +18,21 @@
 		ref,
 		onUnmounted,
 		nextTick,
-		computed
+		computed,
 	} from "vue";
-	import {
-		useH5Camera
-	} from "@/components/zhuapaiConfirm/useCamera";
 	import * as ksApi from "@/api/kaoshi.js"
 	import {
 		getStaticUrl
 	} from "@/utils/common.js"
+	
+	import {useZhuapaiStore} from "@/store/zhuapai.js"
+	import {getFileUpload} from "@/api/kaoshi.js"
+	
+	const zhuapaiStore = useZhuapaiStore();
 
 	const imgUrl = getStaticUrl('static/images/exam/nokaoshi.png')
 
-	let zhuapaiFun = null;
-	let stopCamera = null;
-	let playVideoFun = null;
+	const cameraContext = ref(null);
 
 	const DropRef = ref(null);
 	const DropContainerRef = ref(null);
@@ -68,7 +64,6 @@
 
 	function showVideoBtn() {
 		showVideo.value = true;
-		playVideoFun && playVideoFun();
 	}
 
 	function touchmove(event) {
@@ -76,14 +71,16 @@
 		let moveX = event.touches[0].pageX - disX.value;
 		let moveY = event.touches[0].pageY - disY.value;
 
-		const systemInfo = uni.getSystemInfoSync();
+		const systemInfo = uni.getAppBaseInfo();
 		const windowHeight = systemInfo.windowHeight; // 可视区域高度 ‌:ml-citation{ref="1,3" data="citationList"}  
 		const windowWidth = systemInfo.windowWidth; // 可视区域高度 ‌:ml-citation{ref="1,3" data="citationList"}  
 
 
 		// 3,获取容器的宽高和拖动元素的宽高  每一次移动都会获取一次 ,建议放在外面进行获取
-		let dragHeight = DropRef.value.$el.offsetHeight;
-		let dragWidth = DropRef.value.$el.offsetWidth;
+		// let dragHeight = DropRef.value.$el.offsetHeight;
+		// let dragWidth = DropRef.value.$el.offsetWidth;
+		let dragHeight = 0;
+		let dragWidth = 0;
 
 		// 4,控制范围:在元素 被拖拽的过程中 判断 元素的定位值 是否到达边界 如果到了 就不能在走了
 		if (moveX <= 0) {
@@ -108,8 +105,10 @@
 	}
 
 	function touchstart(event) {
-		disX.value = event.touches[0].pageX - DropRef.value.$el.offsetLeft;
-		disY.value = event.touches[0].pageY - DropRef.value.$el.offsetTop;
+		// disX.value = event.touches[0].pageX - DropRef.value.$el.offsetLeft;
+		// disY.value = event.touches[0].pageY - DropRef.value.$el.offsetTop;
+		disX.value = 0;
+		disY.value = 0;
 	}
 
 
@@ -126,34 +125,105 @@
 
 		}
 	}
+	
 
 	function startCamera() {
 		// 请求摄像头权限并获取流
-		// #ifdef H5
-		console.log('navigator', navigator)
-		const {
-			startH5Camera,
-			handlePaiZhao,
-			stopH5Camera,
-			playVideo
-		} = useH5Camera({
-			elVideoId: '#videoZhaPai',
-			elCanvasId: '#canvasZhuaPai',
-			onVideoSuccess,
-			onVideoError,
-			zhuapaiHttp: ksApi.getClientZhuaPaiUpdate,
-			operId: operId.value
+		cameraContext.value = uni.createCameraContext();
+	}
+	
+	function urlToBase64(url) {
+		return new Promise((resolve, reject) => {
+			// #ifdef MP-WEIXIN
+			// 微信小程序平台
+			uni.getFileSystemManager().readFile({
+				filePath: url, // 图片临时路径
+				encoding: 'base64', // 指定编码格式
+				success: (res) => {
+					// 拼接Data URL前缀,注意图片类型可能需要根据实际情况调整(如png)
+					let base64 = 'data:image/jpeg;base64,' + res.data;
+					resolve(base64);
+				},
+				fail: (err) => {
+					reject(err);
+				}
+			});
+			// #endif
+		});
+	}
+	
+	
+	function getSnapShotImage(data) {
+		urlToBase64(data).then((d1) => {
+			const imgData = d1.split(';base64,');
+			
+			if (!imgData.length) {
+				console.error('【源 :拍照数据异常,未找到图片二进制数据分割节点: `;base64,`】');
+				return;
+			}
+			const opt = {
+				data: imgData[1],
+				prefix: 'kaoshi/zhuapai',
+				suffix: 'png',
+				
+			};
+				
+			getFileUpload(opt).then(res => {
+				const dOption = {
+					operId:operId.value,
+					url: res.data
+				}
+				ksApi.getClientZhuaPaiUpdate(dOption)
+					.then(res => {
+						console.log('【源 : 获取抓拍数据】');
+					})
+					.catch(err => {
+						console.error('源 :抓拍接口异常', err);
+						uni.showToast({
+							icon: 'none',
+							title: '抓拍图片异常!'
+						})
+						uni.redirectTo({
+							url: "/pages/client/Kaoshi/list"
+						})
+					});
+			}).catch(err => {
+				uni.showToast({
+					icon: 'none',
+					title: '当前网络可能存在异常,请稍后重试,如持续异常,请联系管理员。注:若异常未联系管理员,可能会影响考试结果。'
+				})
+				uni.redirectTo({
+					url: "/pages/client/Kaoshi/list"
+				})
+			})
 		})
-		startH5Camera();
-		zhuapaiFun = handlePaiZhao;
-		stopCamera = stopH5Camera;
-		playVideoFun = playVideo;
-		// #endif
-
+		
+	}
+	
+	
+	function doZhuaiPai(ImageFile) {
+		try {
+			if (zhuapaiStore.status == 0) {
+				getSnapShotImage(ImageFile);
+			} else {
+				const ImageFile1 = imgUrl.value;
+				getSnapShotImage(ImageFile1);
+			}
+		} catch (err) {
+			console.error('源 :绘图失败', err);
+		}
 	}
 
 	function handleZhua() {
-		zhuapaiFun && zhuapaiFun()
+		cameraContext.value.takePhoto({
+			quality: 'high',
+			success: (res) => {
+			  doZhuaiPai(res.tempImagePath)
+			},
+			fail: (err) => {
+			  console.error('拍照失败:', err);
+			}
+		});
 	}
 
 	function onVideoSuccess() {
@@ -161,12 +231,10 @@
 			// 首次运行进行抓拍一次
 			handleZhua();
 		}, 3000);
-		addVideoListener();
 	}
 
 	function onVideoError() {
 		emits('error')
-		removeVideoListener()
 	}
 
 	// 针对视频通话的监听处理
@@ -198,24 +266,6 @@
 			console.log('结束')
 		}, 10 * 1000)
 	}
-   function addVideoListener() {
-		let video = document.querySelector(`#videoZhaPai .uni-video-video`)
-		// 判定有流
-		video.addEventListener('progress', onProgress);
-		video.addEventListener('timeupdate', onTimeupdate);
-	}
-     function removeVideoListener() {
-		let video =document.querySelector(`#videoZhaPai .uni-video-video`)
-		video && video.removeEventListener('progress', onProgress);
-		video && video.removeEventListener('timeupdate', onTimeupdate);
-	}
-
-
-	onUnmounted(() => {
-		// 组件销毁时停止摄像头
-		stopCamera && stopCamera();
-		removeVideoListener();
-	})
 
 	defineExpose({
 		init,

+ 19 - 47
pages/client/Kaoshi/exam.vue

@@ -80,17 +80,12 @@
 				</view>
 			</view>
 		</uni-popup>
-		<!-- 摄像头确认 -->
-		<zhuapaiConfirm ref="zhuapaiConfirmRef" @success="zpConfirmSuccess" @error="zpConfirmError" 
-			@cancel="zpConfirmCancel" key="1"></zhuapaiConfirm>
+		<!-- 摄像头 -->
 		<template v-if="data.zhuapai && data.zhuapai > 0">
 			<!-- 抓拍 -->
 			<zhuapaiVue ref="zhuapaiRef" @error="zpError" @success="zpSuccess" key="2" @progress="onProgress"></zhuapaiVue>
 		</template>
-	
-		<!-- 切屏 -->
-		<qiepingVue ref="qiepingRef" @zhuapai="qpZhuapai" @forceSubmit="forceSubmit" @qiepingToast="qiepingToast"
-			key="3"></qiepingVue>
+
 		<!-- 交卷确认 -->
 		<answerQueren ref="answerQrRef" @confirm="handleQuerenConfirm"></answerQueren>
 		<!-- 考试得分 -->
@@ -110,12 +105,11 @@
 		nextTick
 	} from "vue";
 	import zhuapaiVue from "@/components/zhuapaiConfirm/zhuapai.vue";
-	import qiepingVue from "@/components/zhuapaiConfirm/qieping.vue";
 	import zhuapaiConfirm from "@/components/zhuapaiConfirm/index.vue";
 	import answerQueren from "@/components/zhuapaiConfirm/answerQueren.vue";
 	import submitScoreVue from "@/components/zhuapaiConfirm/submitScore.vue";
 	import {
-		onLoad
+		onLoad, onShow, onHide
 	} from "@dcloudio/uni-app";
 	import * as ksApi from "@/api/kaoshi.js"
 	import danxuan from "@/components/questions/danxuan.vue";
@@ -129,6 +123,7 @@
 		useKaoShiCache
 	} from "./examTools"
 	import qiepingDlVue from "@/components/dialog/qiepingDl.vue";
+	import {useQiePing} from "@/utils/useQieping.js"
 
 	const {
 		checkDanxuanReply,
@@ -142,23 +137,28 @@
 		getCacheKs,
 		removeCacheKs
 	} = useKaoShiCache();
+	
+	const { init: qiepingInit } = useQiePing();
 
 	onLoad((option) => {
 		data.ksId = option.ksId;
 		data.zhuapai = option.zhuapai;
 		data.userKaozhengId = option.userKaozhengId;
 		data.from = option.from;
-		if (data.zhuapai && data.zhuapai != 0) {
+		
+		initKaoshi();
+		
+		/* if (data.zhuapai && data.zhuapai != 0) {
 			// 考试前确认摄像头
 			nextTick(() => {
 				initBeforKaoshi();
 			})
 		} else {
+			
 			initKaoshi();
-		}
+		} */
 	})
-
-
+	
 	const popupRef = ref(null)
 	const zhuapaiRef = ref(null)
 	const qiepingRef = ref(null)
@@ -415,9 +415,6 @@
 			title: '抓拍图片异常',
 			icon: 'none'
 		})
-		/* uni.redirectTo({
-			url: '/pages/client/Kaoshi/list'
-		}) */
 		handleBack()
 	}
 
@@ -436,20 +433,10 @@
 	}
 
 	function zpConfirmError() {
-		// uni.showToast({
-		// 	title: '摄像头唤起异常',
-		// 	icon: 'none'
-		// })
-		/* uni.redirectTo({
-			url: '/pages/client/Kaoshi/list'
-		}) */
 		handleBack()
 	}
 
 	function zpConfirmCancel() {
-		/* uni.redirectTo({
-			url: '/pages/client/Kaoshi/list'
-		}) */
 		handleBack()
 	}
 
@@ -505,19 +492,6 @@
 		 if (pages.length>1) {
 			 uni.navigateBack()
 		 } else {
-			 /* if (data.from == 'shouye') {
-			 	uni.redirectTo({
-			 		url: "/pages/client/ShouYe/shouye"
-			 	})
-			 } else if (data.from == 'kaoshiList') {
-			 	uni.redirectTo({
-			 		url: "/pages/client/Kaoshi/list"
-			 	})
-			 } else {
-			 	uni.redirectTo({
-			 		url: "/pages/client/ShouYe/shouye"
-			 	})
-			 } */
 			  history.back();
 		 }
 		
@@ -660,9 +634,6 @@
 			operId: data.operId,
 			biaoji: JSON.stringify(data.biaoji)
 		}).catch(err => {
-			/* uni.redirectTo({
-				url: '/pages/client/Kaoshi/list'
-			}) */
 			handleBack()
 		})
 	}
@@ -688,7 +659,6 @@
 
 	// 摄像头确认初始化
 	function initBeforKaoshi() {
-		console.log(zhuapaiConfirmRef.value)
 		zhuapaiConfirmRef.value.showDialog()
 	}
 
@@ -729,20 +699,22 @@
 			// 设置缓存
 			formatKaoshiData();
 			// 设置抓拍监听
-			
 			if (data.zhuapai && data.zhuapai > 0) {
 				zhuapaiRef.value.init({
 					zhuapai: zhuapai,
 					operId: operId
 				});
 			}
-			
-			// 设置切屏监听
-			qiepingRef.value.init({
+			// 设置切屏
+			qiepingInit({
 				zhuapaiFlag: true,
 				toggleScreenFlag: toggleScreenFlag,
 				toggleScreenSecond: toggleScreenSecond,
 				ksId: data.ksId
+			}, {
+				zhuapai:qpZhuapai,
+				forceSubmit,
+				qiepingToast
 			})
 
 			uni.setNavigationBarTitle({

+ 55 - 0
pages/client/Kaoshi/examCamera.vue

@@ -0,0 +1,55 @@
+<template>
+	<view>
+		<zhuapaiConfirm ref="zhuapaiConfirmRef" @success="zpConfirmSuccess" @error="zpConfirmError"
+			@cancel="zpConfirmCancel" key="1"></zhuapaiConfirm>
+	</view>
+</template>
+
+<script setup>
+	import {
+		onLoad,
+		onShow,
+		onHide
+	} from "@dcloudio/uni-app";
+	import {
+		ref,nextTick
+	} from "vue";
+	import zhuapaiConfirm from "@/components/zhuapaiConfirm/index.vue";
+
+	const opt = ref(null);
+	const zhuapaiConfirmRef = ref(null);
+
+	onLoad((options) => {
+		opt.value = options;
+		nextTick(() => {
+			zhuapaiConfirmRef.value.showDialog()
+		})
+	})
+
+	function zpConfirmSuccess() {
+		uni.redirectTo({
+			url: `/pages/client/Kaoshi/exam?ksId=${opt.value.ksId}&zhuapai=${opt.value.zhuapai}&userKaozhengId=${opt.value.userKaozhengId}&from=${opt.value.from}`
+		})
+	}
+
+	function zpConfirmError() {
+		handleBack();
+	}
+
+	function zpConfirmCancel() {
+		handleBack();
+	}
+
+	function handleBack() {
+		const pages = getCurrentPages();
+		if (pages.length > 1) {
+			uni.navigateBack()
+		} else {
+			history.back();
+		}
+	}
+</script>
+
+<style>
+
+</style>

+ 1 - 1
pages/client/Kaoshi/list.vue

@@ -164,7 +164,7 @@
 		}, '', window.location.href);
 		// #endif
 		uni.navigateTo({
-			url: `/pages/client/Kaoshi/exam?ksId=${item.ksId}&zhuapai=${activeks.value.zhuapai}&userKaozhengId=${activeks.value.userKaozhengId}&from=kaoshiList`
+			url: `/pages/client/Kaoshi/examCamera?ksId=${item.ksId}&zhuapai=${activeks.value.zhuapai}&userKaozhengId=${activeks.value.userKaozhengId}&from=kaoshiList`
 		})
 	}