Jelajahi Sumber

调整页面

wangxy 2 bulan lalu
induk
melakukan
95966bd5a7

+ 17 - 3
api/kaoshi.js

@@ -12,8 +12,21 @@ export function getKaoshiList(data = {}) {
   })
 }
 
+
 export function getKaoshiInfo(data = {}) {
   return request({
+    url: '/app/kaoshi/guanliyuan/info',
+    headers: {
+      isToken: false
+    },
+    method: 'post',
+    data,
+    timeout: 20000
+  })
+}
+
+export function getClientKaoshiInfo(data = {}) {
+  return request({
     url: '/app/kaoshi/info',
     headers: {
       isToken: false
@@ -36,9 +49,10 @@ export function getClientKaoshiList(data = {}) {
   })
 }
 
-export function getClientKaoshiInfo(data = {}) {
+
+export function getClientZhuaPaiUpdate(data = {}) {
   return request({
-    url: '/app/kaoshi/guanliyuan/info',
+    url: '/app/kaoshi/zhuapai',
     headers: {
       isToken: false
     },
@@ -46,4 +60,4 @@ export function getClientKaoshiInfo(data = {}) {
     data,
     timeout: 20000
   })
-}
+}

+ 20 - 0
components/identification/identification.vue

@@ -0,0 +1,20 @@
+<template>
+	<view>
+		身份确认
+	</view>
+</template>
+
+<script>
+	export default {
+		name:"identification",
+		data() {
+			return {
+				
+			};
+		}
+	}
+</script>
+
+<style lang="scss">
+
+</style>

+ 1 - 1
components/kaoshixuzhi/kaoshixuzhi.vue

@@ -59,7 +59,7 @@
 	}
 
 	function handleConfirm() {
-		emits('confirm', data.ksId);
+		emits('confirm', data);
 		popupRef.value.close()
 	}
 

+ 1 - 1
components/kaoshixuzhi/lianxixuzhi.vue

@@ -59,7 +59,7 @@
 	}
 
 	function handleConfirm() {
-		emits('confirm', data.lxId);
+		emits('confirm', data);
 		popupRef.value.close()
 	}
 

+ 119 - 0
components/zhuapaiConfirm/index.vue

@@ -0,0 +1,119 @@
+<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" 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;">摄像头正在初始化...</view>
+				<video v-show="showConfirmBtn" ref="videoRef" style="width:100%; height: 320rpx;" id="videoConfirm"
+					:controls="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> -->
+			</view>
+		</uni-popup-dialog>
+	</uni-popup>
+</template>
+
+<script setup>
+	import {
+		ref,
+		onUnmounted,
+		onMounted,
+		nextTick
+	} from "vue"
+	import {
+		useH5Camera
+	} from "./useCamera.js"
+	
+	const emits = defineEmits(['success', 'error', 'cancel'])
+	
+	const popupRef = ref(null)
+	const showConfirmBtn = ref(false);
+	
+	let zhuapaiFun = null;
+	let stopCamera = null;
+
+	function startCamera() {
+		// 请求摄像头权限并获取流
+		// #ifdef H5
+		console.log('navigator', navigator)
+		const {
+			startH5Camera,
+			handlePaiZhao,
+			stopH5Camera
+		} = useH5Camera({
+			elVideoId: '#videoConfirm',
+			elCanvasId: '#canvasConfirm',
+			onVideoSuccess,
+			onVideoError
+		})
+		startH5Camera();
+		zhuapaiFun = handlePaiZhao;
+		stopCamera = stopH5Camera;
+		// #endif
+
+		// #ifdef APP-PLUS
+		console.log('App端暂时不支持摄像头功能')
+		// #endif
+	}
+
+	function handleZhua() {
+		zhuapaiFun()
+	}
+
+
+	function onVideoSuccess() {
+		showConfirmBtn.value = true;
+	}
+
+	function onVideoError() {
+		showConfirmBtn.false = true;
+		emits('error')
+	}
+
+	function showDialog() {
+		popupRef.value.open();
+		nextTick(() => {
+			startCamera()
+		})
+	}
+
+	function handleClose() {
+		emits('cancel')
+		popupRef.value.close();
+		stopCamera && stopCamera()
+	}
+
+	function handleConfirm() {
+		emits('success')
+		popupRef.value.close();
+		stopCamera && stopCamera()
+	}
+
+	defineExpose({
+		showDialog
+	})
+
+	onUnmounted(() => {
+		// 组件销毁时停止摄像头
+		stopCamera && stopCamera();
+	})
+</script>
+
+<style lang="scss">
+	.phone-camera-box {
+		width: 100%;
+	}
+
+	.uni-video-container {
+		width: 100%;
+	}
+
+	.uni-video-video {
+		width: 100%;
+	}
+</style>

+ 14 - 0
components/zhuapaiConfirm/qieping.vue

@@ -0,0 +1,14 @@
+<template>
+	<view></view>
+</template>
+
+<script setup>
+	import {ref} from "vue";
+	
+	defineEmits([ ])
+	
+	function init() {}
+</script>
+
+<style>
+</style>

+ 427 - 0
components/zhuapaiConfirm/useCamera.js

@@ -0,0 +1,427 @@
+const errorMessage = {
+	ms1: '请使用微信、Chrome、Firefox或Safari浏览器,如果浏览器没有问题,请联系管理员',
+	ms2: '请使用微信、Chrome、Firefox或Safari',
+	ms3: 'navigator对象无媒体属性', // 错误提示同ms2
+	ms4: '未找到摄像头,请确认摄像头是否正常以及当前摄像头是否被禁用',
+	ms5: '检测到当前摄像头已被占用,请关闭摄像头后重新尝试',
+	ms6: '摄像头硬件无法满足使用要求,请更换摄像头后重新尝试',
+	ms7: '请开启浏览器摄像头权限',
+	ms8: '未获取摄像头数据,请检测摄像头是否正常',
+	ms9: '当前浏览器不支持,请更换浏览器后尝试',
+	ms10: '当前Android系统版本低于9!请更新操作系统',
+	ms11: '当前IOS系统版本低于14.3!请更新操作系统',
+	ms12: '推荐使用safari浏览器或微信,使用其他浏览器可能会在考试过程中出现摄像头问题,影响考试结果,导致重考,不建议使用其他浏览器。',
+	ms13: '推荐使用火狐浏览器、谷歌浏览器或微信,使用其他浏览器可能会在考试过程中出现摄像头问题,影响考试结果,导致重考,不建议使用其他浏览器',
+};
+
+export {
+	errorMessage
+};
+
+
+function checkPlatform2() {
+	const ua = navigator.userAgent.toLowerCase();
+	// 安卓系统
+	if (/android/i.test(navigator.userAgent)) {
+		let test = /android\s([\w.]+)/;
+		let match = test.exec(ua);
+		let version = match[1].split('.')[0];
+		if (version < 9) {
+			Toast.fail(errorMessage.ms10);
+			return {
+				data: false,
+				waitCode: false
+			};
+		}
+		// 判断 浏览器 Android
+		if (!checkAndroidForBrowser()) {
+			// 提示信息
+			Toast.fail({
+				message: errorMessage.ms13,
+				duration: 5000
+			});
+			return {
+				data: true,
+				waitCode: true
+			};
+		}
+		return {
+			data: true,
+			waitCode: false
+		};
+	}
+	// ios 系统
+	if (/(iphone | ipad | ipod | iOS)/i.test(navigator.userAgent)) {
+		let test = /os\s([\w]+)/;
+		let match = test.exec(ua);
+		let vs = match[1].split('_');
+		let version = '';
+
+		if (vs.length > 2) {
+			version = `${vs[0]}.${vs[1]}`;
+		} else if (vs.length == 2) {
+			version = `${vs[0]}.${vs[1]}`;
+		} else {
+			version = `${vs[0]}.0`;
+		}
+
+		if (version < 14.3) {
+			Toast.fail(errorMessage.ms11);
+			return {
+				data: false,
+				waitCode: false
+			};
+		}
+
+		// 判断浏览器兼容 判断 ios 浏览器提示信息
+		// 判断 浏览器 Android
+		if (!checkIosForBrowser()) {
+			// 提示信息
+			Toast.fail({
+				message: errorMessage.ms12,
+				duration: 5000
+			});
+			return {
+				data: true,
+				waitCode: true
+			};
+		}
+
+		return {
+			data: true,
+			waitCode: false
+		};
+	}
+}
+
+function checkIosForBrowser() {
+	let u = navigator.userAgent;
+	let result = false;
+	let curname = getBrowser();
+	// 如果是 苹果
+	if (curname === 'safari') {
+		result = true;
+	}
+	// 如果是 微信
+	if (u.indexOf('MicroMessenger') > -1) {
+		result = true;
+	}
+	return result;
+}
+
+function checkAndroidForBrowser() {
+	let curname = getBrowser();
+	let result = false;
+	// 如果是 谷歌
+	if (curname === 'chrome') {
+		result = true;
+	}
+	if (curname === 'firefox') {
+		result = true;
+	}
+	// 如果是 微信
+	if (curname === 'wechat') {
+		result = true;
+	}
+	return result;
+}
+
+function getBrowser() {
+	var u = navigator.userAgent;
+
+	var bws = [{
+		name: 'sgssapp',
+		it: /sogousearch/i.test(u),
+	}, {
+		name: 'wechat',
+		it: /MicroMessenger/i.test(u),
+	}, {
+		name: 'weibo',
+		it: !!u.match(/Weibo/i),
+	}, {
+		name: 'uc',
+		it: !!u.match(/UCBrowser/i) || u.indexOf(' UBrowser') > -1,
+	}, {
+		name: 'sogou',
+		it: u.indexOf('MetaSr') > -1 || u.indexOf('Sogou') > -1,
+	}, {
+		name: 'xiaomi',
+		it: u.indexOf('MiuiBrowser') > -1,
+	}, {
+		name: 'baidu',
+		it: u.indexOf('Baidu') > -1 || u.indexOf('BIDUBrowser') > -1,
+	}, {
+		name: '360',
+		it: u.indexOf('360EE') > -1 || u.indexOf('360SE') > -1,
+	}, {
+		name: '2345',
+		it: u.indexOf('2345Explorer') > -1,
+	}, {
+		name: 'edge',
+		it: u.indexOf('Edge') > -1,
+	}, {
+		name: 'ie11',
+		it: u.indexOf('Trident') > -1 && u.indexOf('rv:11.0') > -1,
+	}, {
+		name: 'ie',
+		it: u.indexOf('compatible') > -1 && u.indexOf('MSIE') > -1,
+	}, {
+		name: 'firefox',
+		it: u.indexOf('Firefox') > -1,
+	}, {
+		name: 'safari',
+		it: u.indexOf('Safari') > -1 && u.indexOf('Chrome') === -1 && u.indexOf('(KHTML, like Gecko) Version') >
+			-1 && u.indexOf('MQQBrowser') === -1 && u.indexOf('FingerBrowser') === -1,
+	}, {
+		name: 'qqbrowser',
+		it: u.indexOf('MQQBrowser') > -1 && u.indexOf(' QQ') === -1,
+	}, {
+		name: 'qq',
+		it: u.indexOf('QQ') > -1,
+	}, {
+		name: 'chrome',
+		it: u.indexOf('(KHTML, like Gecko) Chrome') > -1 && u.indexOf('MiuiBrowser') === -1 && u.indexOf(
+			'UCBrowser') === -1 && u.indexOf('HarmonyOS') === -1 && u.indexOf('HuaweiBrowser') === -1,
+	}, {
+		name: 'opera',
+		it: u.indexOf('Opera') > -1 || u.indexOf('OPR') > -1,
+	}, {
+		name: 'wechat',
+		it: /MicroMessenger/i.test(u)
+	}, ];
+
+	for (var i = 0; i < bws.length; i++) {
+		if (bws[i].it) {
+			return bws[i].name;
+		}
+	}
+
+	return 'other';
+}
+
+export function errorFunComplete(e) {
+	const name = e.name;
+	if (name === 'NotFoundError' || name === 'DevicesNotFoundError') {
+		Toast.fail(errorMessage.ms4);
+	}
+	if (name === 'NotReadableError' || name === 'TrackStartError') {
+		Toast.fail(errorMessage.ms5);
+	} else if (name === 'OverconstrainedError' || name === 'ConstraintNotSatisfiedError') {
+		Toast.fail(errorMessage.ms6);
+	} else if (name === 'NotAllowedError' || name === 'PermissionDeniedError') {
+		Toast.fail(errorMessage.ms7);
+	} else if (name === 'TypeError' || name === 'TypeError') {
+		Toast.fail(errorMessage.ms8);
+	} else {
+		Toast.fail(errorMessage.ms9);
+	}
+}
+
+let constraints = {
+	audio: false,
+	video: {
+		width: 480,
+		height: 320,
+		sourceId: 'default',
+		deviceId: 'default',
+		transform: 'rotate(180deg)',
+		facingMode: {
+			// exact: 'user'
+		},
+	},
+};
+
+// 校验权限
+export function check(success, error, backFun) {
+
+	if (!navigator) {
+		Toast.fail({
+			message: errorMessage.ms1,
+			duration: 5000
+		});
+		// 当前浏览器版本 无媒体对象
+		backFun && backFun();
+		return false;
+	}
+
+	const resoutData = checkPlatform2();
+	const timeD = resoutData.waitCode ? 5000 : 0;
+	if (!resoutData.data) {
+		backFun && backFun();
+		return false;
+	}
+
+	setTimeout(() => {
+		if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
+			//最新的标准API 返回promise
+			navigator.mediaDevices.getUserMedia(constraints).then(success).catch(error);
+		} else if (navigator.webkitGetUserMedia) {
+			//webkit核心浏览器
+			navigator.webkitGetUserMedia(constraints, success, error);
+
+		} else if (navigator.mozGetUserMedia) {
+			//firfox浏览器
+			navigator.mozGetUserMedia(constraints, success, error);
+
+		} else if (navigator.getUserMedia) {
+			//旧版API
+			navigator.getUserMedia(constraints, success, error);
+		} else {
+			Toast.fail(errorMessage.ms2);
+			backFun && backFun();
+		}
+	}, timeD);
+	// 没有媒体对象
+	// Toast.fail(errorMessage.ms2);
+	// 1. ios 14.3版本一下
+	// 2. 当前浏览器非完整版
+}
+
+// 抓拍确认
+export function check2(success, error) {
+
+
+	if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
+		//最新的标准API 返回promise
+		navigator.mediaDevices.getUserMedia(constraints).then(success).catch(error);
+	} else if (navigator.webkitGetUserMedia) {
+		//webkit核心浏览器
+		navigator.webkitGetUserMedia(constraints, success, error);
+
+	} else if (navigator.mozGetUserMedia) {
+		//firfox浏览器
+		navigator.mozGetUserMedia(constraints, success, error);
+	} else if (navigator.getUserMedia) {
+		//旧版API
+		navigator.getUserMedia(constraints, success, error);
+	}
+}
+
+import {
+	ref,
+	nextTick
+} from "vue"
+// H5 播放抓拍功能
+export function useH5Camera({
+	elVideoId,
+	elCanvasId,
+	onVideoSuccess, // 成功播放回调
+	onVideoError, // 失败回调
+	zhuapaiHttp, // 抓拍接口将base64 上传
+}) {
+	const videoRef = ref('');
+	videoRef.value = document.querySelector(`${elVideoId} .uni-video-video`);
+
+	function videoSuccessFun(MediaStream) {
+		// 赋值流
+		videoRef.value.srcObject = MediaStream;
+		// 设置video监听 为了确实获取视频播放判断有视频数据流
+		addVideoListener();
+		// 播放video 执行播放操作
+		playVideo();
+	}
+
+	function addVideoListener() {
+		videoRef && videoRef.value.addEventListener('play', onVideoPlay);
+	}
+
+	function removeVideoListener() {
+		videoRef && videoRef.value.removeEventListener('play', onVideoPlay);
+	}
+
+	function playVideo() {
+		if (videoRef.value) {
+			videoRef.value.play();
+		}
+	}
+
+	function onVideoPlay() {
+		onVideoSuccess && onVideoSuccess();
+	}
+
+	function videoErrorFun(e) {
+		console.log('错误', e)
+		removeVideoListener();
+		onVideoError && onVideoError(e)
+	}
+
+	// 主动开启
+	function startH5Camera() {
+		check2(videoSuccessFun, videoErrorFun);
+	}
+
+	// 主动关闭
+	function stopH5Camera() {
+		// 重置虚拟流
+		const stream = videoRef && videoRef.value.srcObject;
+		if (!stream) {
+			return;
+		}
+
+		const tracks = stream.getTracks();
+		tracks.forEach(function(track) {
+			track.stop();
+		});
+		// 销毁视频资源
+		videoRef.value.srcObject = null;
+		// 移除监听
+		removeVideoListener && removeVideoListener();
+	}
+
+	function handlePaiZhao() {
+		try {
+			const streamActive = videoRef.value.srcObject.active;
+			// 判断视频流 是否运行
+			if (!streamActive) {
+				onVideoError && onVideoError(new Error('摄像头抓拍异常'))
+				return;
+			}
+		} catch (e) {
+			onVideoError && onVideoError(new Error('摄像头抓拍异常'))
+			return;
+		}
+
+		try {
+			let canvas = document.querySelector(`${elCanvasId} .uni-canvas-canvas`);
+			let context = canvas.getContext('2d');
+			context.drawImage(videoRef.value,  0, 0, videoRef.value.clientWidth, videoRef.value.clientHeight);
+			const ImageFile = context.canvas.toDataURL('image/png');
+			getSnapShotImage(ImageFile);
+		} catch (err) {
+			console.error('源 :绘图失败', err);
+		}
+	}
+
+	function getSnapShotImage(data) {
+		console.log('base64',data)
+		const imgData = data.split(';base64,');
+		if (!imgData.length) {
+			console.error('【源 :拍照数据异常,未找到图片二进制数据分割节点: `;base64,`】');
+			return;
+		}
+		const opt = {
+			data: imgData[1],
+			prefix: 'kaoshi/zhuapai',
+			suffix: 'png',
+		};
+		
+		console.log('optoptopt',opt)
+		zhuapaiHttp && zhuapaiHttp(opt)
+			.then(res => {
+				console.log('【源 : 获取抓拍数据】');
+				this.$emit('getImage', res.data);
+			})
+			.catch(err => {
+				console.error('源 :抓拍接口异常', err);
+				this.$router.push({
+					name: 'examList'
+				});
+			});
+	}
+
+	return {
+		startH5Camera,
+		stopH5Camera,
+		handlePaiZhao
+	}
+}

+ 157 - 0
components/zhuapaiConfirm/zhuapai.vue

@@ -0,0 +1,157 @@
+<template>
+	<view id="Drop" :style="style" @touchmove="touchmove($event)" @touchstart="touchstart($event)" class="dropContainer">
+		<view class="phone-camera-box-zhuapai">
+			<video ref="videoRef" :class="{
+				'show-video': showVideo,
+				'hidden-video': !showVideo
+			}" style="width:100%; height: 150rpx;" id="videoZhaPai" :controls="false"></video>
+
+			<!-- 隐藏抓拍绘制图片 -->
+			<canvas id="canvasZhuaPai" :class="{
+				'show-video': showVideo,
+				'hidden-video': !showVideo
+			}"  style="width:100%; height:  150rpx;"></canvas>
+			<!-- 用于抓拍切出去传递固定img-->
+			<!-- #ifdef H5 -->
+			<img :src="imgUrl" alt="" ref="gudingImg" v-show="false">
+			<!-- #endif -->
+			<!-- 测试抓拍使用 -->
+			<!-- <button @click="handleZhua">抓拍</button> -->
+		</view>
+		<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>
+
+<script setup>
+	import {
+		ref,
+		onUnmounted,
+		nextTick
+	} from "vue";
+	import {
+		useH5Camera
+	} from "@/components/zhuapaiConfirm/useCamera";
+	import * as ksApi from "@/api/kaoshi.js"
+	import {
+		getStaticUrl
+	} from "@/utils/common.js"
+
+	const imgUrl = getStaticUrl('static/images/exam/nokaoshi.png')
+
+	let zhuapaiFun = null;
+	let stopCamera = null;
+
+	const zhuapai = ref(0); // 单位分
+	const showVideo = ref(true);
+	const style = ref({
+		top: "10vh",
+		right: "0",
+	});
+
+	const emits = defineEmits(['init', 'success', 'error', 'cancel'])
+
+	function noShowVideoBtn() {
+		showVideo.value = false
+	}
+
+	function showVideoBtn() {
+		showVideo.value = true
+	}
+
+	function touchmove(event) {
+		console.log(4444, event)
+	}
+
+	function touchstart(event) {
+		console.log(3333, event)
+	}
+
+
+	function init(options) {
+		zhuapai.value = options.zhuapai;
+		if (zhuapai.value > 0) {
+			// 启动摄像头
+			nextTick(() => {
+				startCamera()
+			})
+			// 设定计时器
+			setInterval(() => handleZhua(), zhuapai.value * 60 * 1000 || 6000000)
+		}
+	}
+
+	function startCamera() {
+		// 请求摄像头权限并获取流
+		// #ifdef H5
+		console.log('navigator', navigator)
+		const {
+			startH5Camera,
+			handlePaiZhao,
+			stopH5Camera
+		} = useH5Camera({
+			elVideoId: '#videoZhaPai',
+			elCanvasId: '#canvasZhuaPai',
+			onVideoSuccess,
+			onVideoError,
+			zhuapaiHttp: ksApi.getClientZhuaPaiUpdate
+		})
+		startH5Camera();
+		zhuapaiFun = handlePaiZhao;
+		stopCamera = stopH5Camera;
+		// #endif
+
+	}
+
+	function handleZhua() {
+		zhuapaiFun && zhuapaiFun()
+	}
+
+	function onVideoSuccess() {
+		setTimeout(() => {
+			// 首次运行进行抓拍一次
+			// handleZhua();
+		}, 3000);
+	}
+
+	function onVideoError() {
+		emits('error')
+	}
+
+	onUnmounted(() => {
+		// 组件销毁时停止摄像头
+		stopCamera && stopCamera();
+	})
+
+	defineExpose({
+		init
+	})
+</script>
+
+<style lang="scss" scoped>
+	.dropContainer {
+		width: 30vw;
+		height: 150rpx;
+		margin: 0;
+		padding: 0;
+		// position: absolute;
+		// top: 0;
+		// left: 0;
+		z-index: 10;
+		position: absolute;
+		right: 0;
+		top: 30%;
+
+
+		.show-video {
+			z-index: 10
+		}
+
+		.hidden-video {
+			z-index: -10
+		}
+
+
+	}
+
+</style>

+ 59 - 76
pages.json

@@ -7,120 +7,105 @@
 			}
 		},
 		{
-			"path" : "pages/admin/ShouYe/shouye",
-			"style" : 
-			{
-				"navigationBarTitleText" : "总部管理员/跑单员首页"
+			"path": "pages/admin/ShouYe/shouye",
+			"style": {
+				"navigationBarTitleText": "总部管理员/跑单员首页"
 			}
 		},
 		{
-			"path" : "pages/client/ShouYe/shouye",
-			"style" : 
-			{
-				"navigationBarTitleText" : "家政/考试人员首页"
-			}
-		},{
-			"path" : "pages/admin/Jiazheng/index",
-			"style" : 
-			{
-				"navigationBarTitleText" : "家政"
-			}
-		},{
-			"path" : "pages/admin/Jiazheng/jiazhengUserInfo",
-			"style" : 
-			{
-				"navigationBarTitleText" : "个人信息"
-			}
-		},{
-			"path" : "pages/admin/Jiazheng/jiazhengUserManager",
-			"style" : 
-			{
-				"navigationBarTitleText" : "家政人员管理"
+			"path": "pages/client/ShouYe/shouye",
+			"style": {
+				"navigationBarTitleText": "家政/考试人员首页"
+			}
+		}, {
+			"path": "pages/admin/Jiazheng/index",
+			"style": {
+				"navigationBarTitleText": "家政"
+			}
+		}, {
+			"path": "pages/admin/Jiazheng/jiazhengUserInfo",
+			"style": {
+				"navigationBarTitleText": "个人信息"
+			}
+		}, {
+			"path": "pages/admin/Jiazheng/jiazhengUserManager",
+			"style": {
+				"navigationBarTitleText": "家政人员管理"
 			}
 		},
 		{
-			"path" : "pages/admin/Kaoshi/list",
+			"path": "pages/admin/Kaoshi/list",
 			"style": {
 				"navigationStyle": "custom"
 			}
 		},
 		{
-			"path" : "pages/admin/Kaoshi/exam",
-			"style" : 
-			{
-				"navigationBarTitleText" : "考试",
+			"path": "pages/admin/Kaoshi/exam",
+			"style": {
+				"navigationBarTitleText": "考试",
 				"navigationStyle": "custom"
 			}
 		},
 		{
-			"path" : "pages/admin/Kecheng/list",
-			"style" : 
-			{
+			"path": "pages/admin/Kecheng/list",
+			"style": {
 				"navigationStyle": "custom"
 			}
 		},
 		{
-			"path" : "pages/demo/demo1",
-			"style" : 
-			{
-				"navigationBarTitleText" : "demo1",
+			"path": "pages/demo/demo1",
+			"style": {
+				"navigationBarTitleText": "demo1",
 				"navigationStyle": "custom"
 			}
 		},
 		{
-			"path" : "pages/admin/Kecheng/study",
-			"style" : 
-			{
+			"path": "pages/admin/Kecheng/study",
+			"style": {
 				"navigationStyle": "custom"
 			}
 		},
 		{
-			"path" : "pages/admin/Lianxi/list",
-			"style" : 
-			{
+			"path": "pages/admin/Lianxi/list",
+			"style": {
 				"navigationStyle": "custom"
 			}
 		},
 		{
-			"path" : "pages/admin/Lianxi/lianxi",
-			"style" : 
-			{
+			"path": "pages/admin/Lianxi/lianxi",
+			"style": {
 				"navigationStyle": "custom"
 			}
 		},
 		{
-			"path" : "pages/client/Kaoshi/list",
-			"style" : 
-			{
+			"path": "pages/client/Kaoshi/list",
+			"style": {
 				"navigationStyle": "custom"
 			}
 		},
 		{
-			"path" : "pages/client/Kecheng/list",
-			"style" : 
-			{
-				"navigationBarTitleText" : ""
+			"path": "pages/client/Kecheng/list",
+			"style": {
+				"navigationStyle": "custom"
 			}
 		},
 		{
-			"path" : "pages/client/Lianxi/list",
-			"style" : 
-			{
-				"navigationBarTitleText" : ""
+			"path": "pages/client/Lianxi/list",
+			"style": {
+				"navigationStyle": "custom"
 			}
 		},
 		{
-			"path" : "pages/client/Kaoshi/exam",
-			"style" : 
-			{
-				"navigationBarTitleText" : ""
+			"path": "pages/client/Kaoshi/exam",
+			"style": {
+				"navigationStyle": "custom"
 			}
 		}
 	],
-	 "tabBar": {
-	    "custom": true,
-	    "list": []
-	  },
+	"tabBar": {
+		"custom": true,
+		"list": []
+	},
 	"globalStyle": {
 		"navigationBarTextStyle": "black",
 		"navigationBarTitleText": "麦塔软件",
@@ -128,19 +113,17 @@
 		"backgroundColor": "#F8F8F8",
 		//禁止滑动返回
 		"app-plus": {
-					"popGesture": "none"
-				}
+			"popGesture": "none"
+		}
 	},
 
 	"uniIdRouter": {},
-	"condition" : { //模式配置,仅开发期间生效
+	"condition": { //模式配置,仅开发期间生效
 		"current": 0, //当前激活的模式(list 的索引项)
-		"list": [
-			{
-				"name": "login", //模式名称
-				"path": "pages/Login/index", //启动页面,必选
-				"query": "" //启动参数,在页面的onLoad函数里面得到
-			}
-		]
+		"list": [{
+			"name": "login", //模式名称
+			"path": "pages/Login/index", //启动页面,必选
+			"query": "" //启动参数,在页面的onLoad函数里面得到
+		}]
 	}
 }

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

@@ -7,7 +7,7 @@
 		</view>
 		<!-- 第一行 -->
 		<view class="kaoshi-page-title">
-			<view v-if="activeSt" class="title-types">{{stTypes[activeSt.stTypeId]}}</view>
+			<view v-if="activeSt" class="title-types">{{dlName}}</view>
 			<view>100分钟</view>
 		</view>
 
@@ -144,6 +144,14 @@
 		dlIndex: 0,
 		dtIndex: 0
 	})
+	
+	const dlName = computed(() => {
+		if (data.StListForSearch && activeSt.value) {
+			return data.StListForSearch[activeSt.value.onlyNum].paragraphName
+		} else {
+			return ''
+		}
+	})
 
 	watch(() => data.duanluo, (newVal) => {
 		// 计算已答试题数量
@@ -243,7 +251,7 @@
 
 	function handlePrev() {
 		const qa = data.StListForSearch.find(item => item.stId == activeSt.value.stId);
-		const index = qa.num - 1;
+		const index = qa.onlyNum - 1;
 		if (index > 0) {
 			const result = data.StListForSearch[index - 1];
 			progress.dlIndex = result.dlIndex;
@@ -254,7 +262,7 @@
 
 	function handleNext() {
 		const qa = data.StListForSearch.find(item => item.stId == activeSt.value.stId);
-		const index = qa.num - 1;
+		const index = qa.onlyNum - 1;
 		if (index < data.StListForSearch.length) {
 			const result = data.StListForSearch[index + 1];
 			progress.dlIndex = result.dlIndex;
@@ -263,8 +271,8 @@
 	}
 
 	function formatDuanluoList(dlData) {
-		let uIndex = 0; // 试题num
-		let iDuanluo = 0; // 段落num
+		let uIndex = 0; // 试题onlyNum
+		let iDuanluo = 0; // 段落onlyNum
 		let result = [];
 		for (const duanluo of data.duanluo) {
 			let paragraph = {
@@ -291,7 +299,7 @@
 					paragraphName: paragraph.name,
 					dlIndex: iDuanluo,
 					dtIndex: iDanxuan.iQa,
-					num: iDanxuan.onlyNum
+					onlyNum: iDanxuan.onlyNum
 				})
 			}
 			order = 0;
@@ -312,7 +320,7 @@
 					paragraphName: paragraph.name,
 					dlIndex: iDuanluo,
 					dtIndex: iDuoxuan.iQa,
-					num: iDuoxuan.onlyNum
+					onlyNum: iDuoxuan.onlyNum
 				})
 			}
 			order = 0;
@@ -333,7 +341,7 @@
 					paragraphName: paragraph.name,
 					dlIndex: iDuanluo,
 					dtIndex: iPanduan.iQa,
-					num: iPanduan.onlyNum
+					onlyNum: iPanduan.onlyNum
 				})
 			}
 			order = 0;
@@ -354,7 +362,7 @@
 					paragraphName: paragraph.name,
 					dlIndex: iDuanluo,
 					dtIndex: iTiankong.iQa,
-					num: iTiankong.onlyNum
+					onlyNum: iTiankong.onlyNum
 				})
 			}
 			iDuanluo++;

+ 2 - 4
pages/admin/Kaoshi/list.vue

@@ -95,10 +95,8 @@
 		})
 	}
 
-	function handleConfirmKs(ksId) {
-		checkKaoshi({
-			ksId
-		})
+	function handleConfirmKs(data) {
+		checkKaoshi(data)
 	}
 
 	function checkKsXz(data) {

+ 9 - 1
pages/admin/Lianxi/lianxi.vue

@@ -7,7 +7,7 @@
 		</view>
 		<!-- 第一行 -->
 		<view class="kaoshi-page-title">
-			<view v-if="activeSt" class="title-types">{{stTypes[activeSt.stTypeId]}}</view>
+			<view v-if="activeSt" class="title-types">{{dlName}}</view>
 			<view>100分钟</view>
 		</view>
 
@@ -145,6 +145,14 @@
 		dlIndex: 0,
 		dtIndex: 0
 	})
+	
+	const dlName = computed(() => {
+		if (data.StListForSearch && activeSt.value) {
+			return data.StListForSearch[activeSt.value.onlyNum].paragraphName
+		} else {
+			return ''
+		}
+	})
 
 	watch(() => data.duanluo, (newVal) => {
 		// 计算已答试题数量

+ 2 - 2
pages/admin/Lianxi/list.vue

@@ -88,8 +88,8 @@
 		lxxzRef.value.showDialog(data)
 	}
 	
-	function handleConfirmKs(lxId) {
-		checkKaoshi({lxId})
+	function handleConfirmKs(data) {
+		checkKaoshi(data)
 	}
 	
 	function goUpPage() {

+ 112 - 109
pages/client/Kaoshi/exam.vue

@@ -7,7 +7,12 @@
 		</view>
 		<!-- 第一行 -->
 		<view class="kaoshi-page-title">
-			<view v-if="activeSt" class="title-types">{{stTypes[activeSt.stTypeId]}}</view>
+			<!--  倒计时 -->
+			<view v-if="!!data.endSecond">
+				<text>考试倒计时:</text>
+				<uni-countdown :show-day="true" :second="1000" @timeup="onTimeUp" :start="startCountDown"></uni-countdown>
+			</view>
+			<view v-if="activeSt" class="title-types">{{dlName}}</view>
 			<view>100分钟</view>
 		</view>
 
@@ -42,7 +47,6 @@
 				<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>
@@ -67,20 +71,20 @@
 				</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>
+		<zhuapaiConfirm ref="zhuapaiConfirmRef" 
+			@success="zpConfirmSuccess"
+			@error="zpConfirmError"
+			@cancel="zpConfirmCancel"
+		
+		></zhuapaiConfirm>
+		<!-- 抓拍 -->
+		<zhuapaiVue ref="zhuapaiRef"
+			@error="zpError"
+		></zhuapaiVue>
+		<!-- 切屏 -->
+		<qiepingVue ref="qiepingRef"></qiepingVue>
+		
 	</view>
-
-
-
 </template>
 
 <script setup>
@@ -88,8 +92,12 @@
 		ref,
 		reactive,
 		computed,
-		watch
+		watch,
+		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 {
 		onLoad
 	} from "@dcloudio/uni-app";
@@ -98,9 +106,7 @@
 	import duoxuan from "@/components/questions/duoxuan.vue";
 	import tiankong from "@/components/questions/tiankong.vue";
 	import panduan from "@/components/questions/panduan.vue";
-	import scoreAndAnswerVue from "@/components/scoreAndAnswer/scoreAndAnswerAdmin.vue";
 	import {useQuestionTools} from "@/components/questions/useQuestionTools.js";
-	import scoreAndAnswerAdminTiankong from "@/components/scoreAndAnswer/scoreAndAnswerAdminTiankong.vue";
 	const {
 		checkDanxuanReply,
 		checkDuoxuanReply,
@@ -109,16 +115,25 @@
 		getLetterByIndex
 	} = useQuestionTools();
 
-	const stTypes = {
-		1: '单选题',
-		2: '多选题',
-		3: '判断题',
-		4: '填空题',
-	}
+	onLoad((option) => {
+		data.ksId = option.ksId;
+		data.zhuapai = option.zhuapai
+		
+		if (data.zhuapai) {
+			// 考试前确认摄像头
+			nextTick(() => {
+				initBeforKaoshi();
+			})
+		} else {
+			initKaoshi();
+		}
+	})
+
 
 	const popupRef = ref(null)
-	const scoreAnswerRef = ref(null)
-	const scoreAnswerTkRef = ref(null)
+	const zhuapaiRef = ref(null)
+	const qiepingRef = ref(null)
+	const zhuapaiConfirmRef = ref(null)
 
 	const startCountDown = ref(false);
 
@@ -144,6 +159,14 @@
 		dlIndex: 0,
 		dtIndex: 0
 	})
+	
+	const dlName = computed(() => {
+		if (data.StListForSearch && activeSt.value) {
+			return data.StListForSearch[activeSt.value.onlyNum].paragraphName
+		} else {
+			return ''
+		}
+	})
 
 	watch(() => data.duanluo, (newVal) => {
 		// 计算已答试题数量
@@ -174,10 +197,40 @@
 		}
 	});
 
-	onLoad((option) => {
-		data.ksId = option.ksId;
+	// 摄像头抓拍相关功能 start
+	function zpSuccess() {
+		
+	}
+	function zpError() {
+		uni.showToast({
+			title: '摄像头唤起异常'
+		})
+		uni.redirectTo({
+			url: '/pages/client/Kaoshi/list'
+		})
+	}
+	
+	// 摄像头抓拍相关功能 end
+	// 摄像头确认相关功能 start
+	function zpConfirmSuccess() {
 		initKaoshi();
-	})
+	}
+	function zpConfirmError() {
+		uni.showToast({
+			title: '摄像头唤起异常'
+		})
+		uni.redirectTo({
+			url: '/pages/client/Kaoshi/list'
+		})
+	}
+	function zpConfirmCancel() {
+		uni.redirectTo({
+			url: '/pages/client/Kaoshi/list'
+		})
+	}
+	
+	// 摄像头确认相关功能 end
+	
 
 	function getQaClass(qa) {
 		if (qa.marked && qa.marked === true) {
@@ -243,7 +296,7 @@
 
 	function handlePrev() {
 		const qa = data.StListForSearch.find(item => item.stId == activeSt.value.stId);
-		const index = qa.num - 1;
+		const index = qa.onlyNum - 1;
 		if (index > 0) {
 			const result = data.StListForSearch[index - 1];
 			progress.dlIndex = result.dlIndex;
@@ -254,7 +307,7 @@
 
 	function handleNext() {
 		const qa = data.StListForSearch.find(item => item.stId == activeSt.value.stId);
-		const index = qa.num - 1;
+		const index = qa.onlyNum - 1;
 		if (index < data.StListForSearch.length) {
 			const result = data.StListForSearch[index + 1];
 			progress.dlIndex = result.dlIndex;
@@ -263,8 +316,8 @@
 	}
 
 	function formatDuanluoList(dlData) {
-		let uIndex = 0; // 试题num
-		let iDuanluo = 0; // 段落num
+		let uIndex = 0; // 试题onlyNum
+		let iDuanluo = 0; // 段落onlyNum
 		let result = [];
 		for (const duanluo of data.duanluo) {
 			let paragraph = {
@@ -280,7 +333,6 @@
 				iDanxuan.onlyNum = uIndex + 1;
 				iDanxuan.order = order;
 				iDanxuan.iQa = iQa;
-				iDanxuan.reply = iDanxuan.result;
 				paragraph.qas.push(iDanxuan);
 				uIndex++;
 				order++;
@@ -291,7 +343,7 @@
 					paragraphName: paragraph.name,
 					dlIndex: iDuanluo,
 					dtIndex: iDanxuan.iQa,
-					num: iDanxuan.onlyNum
+					onlyNum: iDanxuan.onlyNum
 				})
 			}
 			order = 0;
@@ -301,7 +353,6 @@
 				iDuoxuan.onlyNum = uIndex + 1;
 				iDuoxuan.order = order;
 				paragraph.qas.push(iDuoxuan);
-				iDuoxuan.reply = iDuoxuan.result;
 				iDuoxuan.iQa = iQa;
 				uIndex++;
 				order++;
@@ -312,7 +363,7 @@
 					paragraphName: paragraph.name,
 					dlIndex: iDuanluo,
 					dtIndex: iDuoxuan.iQa,
-					num: iDuoxuan.onlyNum
+					onlyNum: iDuoxuan.onlyNum
 				})
 			}
 			order = 0;
@@ -322,7 +373,6 @@
 				iPanduan.onlyNum = uIndex + 1;
 				iPanduan.order = order;
 				paragraph.qas.push(iPanduan);
-				iPanduan.reply = iPanduan.result;
 				iPanduan.iQa = iQa;
 				uIndex++;
 				order++;
@@ -333,7 +383,7 @@
 					paragraphName: paragraph.name,
 					dlIndex: iDuanluo,
 					dtIndex: iPanduan.iQa,
-					num: iPanduan.onlyNum
+					onlyNum: iPanduan.onlyNum
 				})
 			}
 			order = 0;
@@ -343,7 +393,6 @@
 				iTiankong.onlyNum = uIndex + 1;
 				iTiankong.order = order;
 				paragraph.qas.push(iTiankong);
-				iTiankong.reply = iTiankong.result.map(item => item[0]);
 				iTiankong.iQa = iQa;
 				uIndex++;
 				order++;
@@ -354,13 +403,13 @@
 					paragraphName: paragraph.name,
 					dlIndex: iDuanluo,
 					dtIndex: iTiankong.iQa,
-					num: iTiankong.onlyNum
+					onlyNum: iTiankong.onlyNum
 				})
 			}
 			iDuanluo++;
 			questionData.value.push(paragraph)
-
-			console.log(questionData.value)
+			console.log('1',questionData.value)
+			console.log('2',data.StListForSearch)
 		}
 	}
 	
@@ -368,73 +417,19 @@
 		activeSt.value.marked = !activeSt.value.marked;
 	}
 	
-	function handleCheckJiexi() {
-		const qa = activeSt.value ;
-		let score = qa.score;
-		let reply = '';
-		let result = '';
-		let answer = qa.answer;
-		if (qa.stTypeId == 1) {
-			// 单选题
-			if (qa.reply && qa.reply.trim() !== '') {
-				reply = getLetterByIndex(qa.reply)
-			} else {
-				reply = '未答'
-			}
-			
-			if (qa.result) {
-				result = getLetterByIndex(qa.result)
-			} else {
-				result = '无答案'
-			}
-		}
-		if (qa.stTypeId == 2) {
-			// 多选题
-			
-			if (qa.reply && qa.reply.length) {
-				reply = qa.reply.map(item => {
-					if (item.trim()) {
-						return getLetterByIndex(item.trim())
-					}
-				}).join(',')
-			} else {
-				reply = '未答'
-			}
-			if (qa.result) {
-				result = qa.result.map(item => {
-					if (item.trim()) {
-						return getLetterByIndex(item.trim())
-					}
-				}).join(',')
-			} else {
-				result = '无答案'
-			}
-		}
-		if (qa.stTypeId == 3) {
-			// 判断题
-			if (qa.reply == 0) {
-				reply = '错误'
-			}else if (qa.reply == 1) {
-				reply = '正确'
-			}
-			if (qa.result == 0) {
-				result = '错误'
-			}else if (qa.result == 1) {
-				result = '正确'
-			}
-		}
-		if (qa.stTypeId == 4) {
-			let reply = qa.reply || [];
-			let result =qa.result || [];
-			// 填空题
-			scoreAnswerTkRef.value.showPopup({score,reply,result,answer})
-		} else {
-			scoreAnswerRef.value.showPopup({
-				score,reply,result,answer
-			})
-		}
+	function saveKsCache() {}
+	function getKsCache() {}
+	function removeKsCache() {}
+	function formatKaoshiData() {}
+	
+	// 摄像头确认初始化
+	function initBeforKaoshi() {
+		console.log(zhuapaiConfirmRef.value)
+		zhuapaiConfirmRef.value.showDialog()
 	}
-
+	
+	
+	
 	function initKaoshi() {
 		ksApi.getKaoshiInfo({
 			ksId: data.ksId
@@ -464,6 +459,14 @@
 			data.zhuapai = zhuapai;
 			data.duanluo = duanluoList;
 			formatDuanluoList(data.duanluo);
+			
+			// 设置缓存
+			formatKaoshiData();
+			// 设置抓拍监听
+			zhuapaiRef.value.init({zhuapai: 1});
+			// 设置切屏监听
+			// qiepingRef.value.init()
+			
 			uni.setNavigationBarTitle({
 				title: data.ksName
 			});

+ 9 - 3
pages/client/Kaoshi/list.vue

@@ -40,12 +40,15 @@
 		<customTabbarClientVue></customTabbarClientVue>
 		<!-- 考试须知 -->
 		<kaoshixuzhiVue ref="ksxzRef" @confirm="handleConfirmKs"></kaoshixuzhiVue>
+		<!-- 身份确认 -->
+		<!-- <identificationVue ref="shenfenRef"></identificationVue> -->
 	</view>
 </template>
 
 <script setup>
 	import customTabbarClientVue from "@/components/custom-tabbar/custom-tabbar-client.vue";
 	import kaoshixuzhiVue from "@/components/kaoshixuzhi/kaoshixuzhi.vue";
+	import identificationVue from "@/components/identification/identification.vue";
 	import {
 		ref,
 		reactive
@@ -56,6 +59,7 @@
 	import * as kaoshiApi from "@/api/kaoshi.js";
 	
 	const ksxzRef = ref(null);
+	const shenfenRef = ref(null)
 
 	const data = reactive({
 		zyName: '', // 职业名称
@@ -77,8 +81,9 @@
 		})
 	}
 	
-	function handleConfirmKs(ksId) {
-		checkKaoshi({ksId})
+	function handleConfirmKs(data) {
+		console.log('ddd',data)
+		checkKaoshi(data)
 	}
 	
 	function checkKsXz(data) {
@@ -143,7 +148,8 @@
 		data.state = 'loading';
 		data.page++;
 		opt.page = data.page;
-		kaoshiApi.getClientKaoshiList(opt).then(res => {
+		// kaoshiApi.getClientKaoshiList(opt).then(res => {
+		kaoshiApi.getKaoshiList(opt).then(res => {
 			data.list = data.list.concat(res.data.data);
 			data.loading = false;
 

+ 2 - 2
pages/client/Lianxi/list.vue

@@ -81,8 +81,8 @@
 		lxxzRef.value.showDialog(data)
 	}
 	
-	function handleConfirmKs(lxId) {
-		checkKaoshi({lxId})
+	function handleConfirmKs(data) {
+		checkKaoshi(data)
 	}
 	
 	function goUpPage() {

+ 7 - 0
static/images/exam/closeVideo.svg

@@ -0,0 +1,7 @@
+<svg t="1690253103663" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6610"
+     id="mx_n_1690253103664" width="50" height="50">
+    <path d="M256 85.333333h682.666667v682.666667h-85.333334v85.333333h85.333334c46.933333 0 85.333333-38.4 85.333333-85.333333V85.333333c0-46.933333-38.4-85.333333-85.333333-85.333333H256C209.066667 0 170.666667 38.4 170.666667 85.333333v85.333334h85.333333V85.333333z"
+          fill="#ffffff" p-id="6611"></path>
+    <path d="M768 170.666667H85.333333C38.4 170.666667 0 209.066667 0 256v682.666667c0 46.933333 38.4 85.333333 85.333333 85.333333h682.666667c46.933333 0 85.333333-38.4 85.333333-85.333333V256c0-46.933333-38.4-85.333333-85.333333-85.333333z m0 768H85.333333V256h682.666667v682.666667z"
+          fill="#ffffff" p-id="6612"></path>
+</svg>

TEMPAT SAMPAH
static/images/exam/nokaoshi.png


+ 1 - 0
static/images/exam/shitiVideo.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1690178518545" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2659" id="mx_n_1690178518546" xmlns:xlink="http://www.w3.org/1999/xlink" width="50" height="50"><path d="M907.712 642.592l-2.624-302.592-204.256 145.056 206.88 157.536z m-39.68-354.784a64 64 0 0 1 101.056 51.648l2.624 302.592a64 64 0 0 1-102.752 51.456l-206.912-157.536a64 64 0 0 1 1.728-103.104l204.256-145.056z" fill="#00807b" p-id="2660"></path><path d="M144 256a32 32 0 0 0-32 32v417.376a32 32 0 0 0 32 32h456.32a32 32 0 0 0 32-32V288a32 32 0 0 0-32-32H144z m0-64h456.32a96 96 0 0 1 96 96v417.376a96 96 0 0 1-96 96H144a96 96 0 0 1-96-96V288a96 96 0 0 1 96-96z" fill="#00807b" p-id="2661"></path></svg>