Просмотр исходного кода

Merge branch 'master' of https://gitee.com/he2802/saas_applet

# Conflicts:
#	pages3/polyv/detail.vue
chenxiong 3 лет назад
Родитель
Сommit
074beb58ea

+ 45 - 0
common/httpList/lock.js

@@ -0,0 +1,45 @@
+import {
+	myRequest
+} from '../request.js'
+export default {
+	/**
+	 * @param {Object} data
+	 * 锁定行为
+	 */
+	lockLockAction(data) {
+		return myRequest({
+			url: '/lock/lockAction',
+			method: 'post',
+			data: data,
+			noLoading:true,
+		})
+	},
+	
+	/**
+	 * @param {Object} data
+	 * 删除锁定行为
+	 */
+	lockDelLock(data) {
+		return myRequest({
+			url: '/lock/delLock',
+			method: 'post',
+			data: data,
+			noLoading:true,
+		})
+	},
+	
+	/**
+	 * @param {Object} data
+	 * 查看锁定状态
+	 */
+	lockLockStatus(data) {
+		return myRequest({
+			url: '/lock/lockStatus',
+			method: 'post',
+			data: data,
+		})
+	},
+	
+	
+	
+}

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
common/isCardTemplate.js


+ 137 - 0
common/socket.js

@@ -0,0 +1,137 @@
+import store from '@/store/index.js'
+import method from '@/common/methodTool'
+let isSocketClose = false; // 是否关闭socket
+let heartbeatInterval = null; // 心跳定时器
+let socketTask = null; // websocket对象
+let againTimer = null; //断线重连定时器
+
+
+let url = null;
+
+/**
+ * sockeUrl:websocet的地址
+ * */
+const sokcet = (sockeUrl) => {
+	url = sockeUrl;
+	isSocketClose = false;
+	//判断是否有websocet对象,有的话清空
+	if (socketTask) {
+		socketTask.close();
+		socketTask = null;
+		clearInterval(heartbeatInterval);
+	}
+
+	// 连接
+	console.log(url)
+	socketTask = uni.connectSocket({
+		url: url,
+		success(data) {
+			console.log("websocket连接成功");
+			clearInterval(againTimer) //断线重连定时器
+		},
+		fail: (err) => {
+			console.log("报错", err);
+		}
+	});
+	// 连接打开
+	socketTask.onOpen((res) => {
+		console.log('WebSocket打开');
+		clearInterval(againTimer) //断线重连定时器
+		clearInterval(heartbeatInterval);
+		// // 30秒发送一次心跳
+		// heartbeatInterval = setInterval(() => {
+		// 	sendMsg('心跳ing')
+		// }, 30000)
+	})
+	// 监听连接失败
+	socketTask.onError((err) => {
+		console.log('WebSocket连接打开失败,请检查', err);
+		//停止发送心跳
+		clearInterval(heartbeatInterval)
+		//如果不是人为关闭的话,进行重连
+		if (!isSocketClose) {
+			reconnect(url)
+		}
+	})
+
+	// // 监听连接关闭 -
+	socketTask.onClose((e) => {
+		console.log('WebSocket连接关闭!',e);
+		clearInterval(heartbeatInterval)
+		if (!isSocketClose) {
+			reconnect(url)
+		}
+	})
+
+	// 监听收到信息
+	socketTask.onMessage((res) => {
+		console.log(res, 'res监听收到信息')
+		
+		if(res.data == 'offLine') {
+			stop();
+			uni.setStorageSync('needToLogin','1')
+			uni.showToast({
+				icon:'none',
+				title:'用户在其他终端登录,强制下线',
+				duration:3000,
+			})
+			setTimeout(() => {
+				method.exit();
+			},3000)
+		}
+	});
+
+
+}
+
+const reconnect = (url) => {
+	console.log('进入断线重连', isSocketClose);
+	clearInterval(againTimer) //断线重连定时器
+	clearInterval(heartbeatInterval);
+	console.log(socketTask)
+	socketTask && socketTask.close(); // 确保已经关闭后再重新打开
+	socketTask = null;
+	// 连接  重新调用创建websocet方法
+	againTimer = setInterval(() => {
+		sokcet(url)
+		console.log('在重新连接中...');
+	}, 20000)
+
+
+}
+
+const sendMsg = (msg) => { //向后端发送心跳包
+	console.log(msg)
+	try {
+		//通过 WebSocket 连接发送数据
+		socketTask.send({
+			data:msg
+		});
+	} catch (e) {
+		console.log(e,'msg')
+		if (isSocketClose) {
+			return
+		} else {
+			reconnect(url)
+		}
+
+	}
+}
+
+const stop = () => {
+	isSocketClose = true
+	clearInterval(heartbeatInterval);
+	clearInterval(againTimer) //断线重连定时器
+	socketTask && socketTask.close(); // 确保已经关闭后再重新打开
+	socketTask = null;
+}
+
+
+
+
+
+export const websocket = {
+	sokcet,
+	stop,
+	sendMsg
+};

+ 69 - 0
components/nav-bar/nav-bar.vue

@@ -0,0 +1,69 @@
+<template>
+	<view>
+		<u-navbar :is-back="showBackBtn" :title="title" z-index="99999999999999">
+			<view class="slot-wrap">
+				<u-icon class="homeIcon" v-if="showHomeBtn" @click="goHome()" name="home"  size="40"></u-icon>
+			</view>
+		</u-navbar>
+	</view>
+</template>
+
+<script>
+import { mapGetters } from 'vuex';
+export default {
+	name: 'navBar',
+	props: {
+		statusBar:{
+			type:Boolean,
+			default:true
+		},
+		title:{
+			type:String,
+			default:''
+		},
+		showBackBtn:{
+			type:Boolean,
+			default:true,
+		},
+		showHomeBtn:{
+			type:Boolean,
+			default:true
+		}
+	},
+	components: {
+	},
+	data() {
+		return {
+			
+		};
+	},
+	onLoad() {},
+	created() {
+	},
+	mounted() {
+		
+	},
+	onPageShow() {
+		
+	},
+	methods: {
+		goHome() {
+			uni.switchTab({
+			    url: '/pages/index/index'
+			});
+		}
+	},
+	computed: { ...mapGetters(['goodsAuditionConfigIdList']) },
+};
+</script>
+
+<style scoped lang="scss">
+	.homeIcon {
+		margin-left:20rpx;
+	}
+	
+	.slot-wrap {
+		display: flex;
+		align-items: center;
+	}
+</style>

+ 366 - 0
pages2/bank/question_record_list.vue

@@ -0,0 +1,366 @@
+<template>
+	<view>
+		<nav-bar title="做题记录" class="nav"></nav-bar>
+		
+		<view class="record">
+			<view class="item" v-for="(record,index) in recordList" :key="index">
+				<view class="note">{{ record.paperName }}</view>
+				<view class="title">{{ record.examName }}</view>
+				<view class="desc">
+					<view>
+						<image src="/static/icon/wk_icon2.png"></image>
+						<text>{{ $method.timestampToTime(record.updateTime, false) }}</text>
+					</view>
+					<view>
+						<image src="/static/icon/wk_icon2.png"></image>
+						<text>总共 {{ record.totalQuestionNum }} 题 做对 {{ record.rightQuestionNum }} 题</text>
+					</view>
+				</view>
+				<view class="btns">
+					<view class="btn" v-if="record.status == 1" @click="doRepeat(record.examId, record.goodsId, record.moduleExamId, record.chapterExamId,index)">重做</view>
+					<view class="btn" @click="questionBankExplain(record)" v-if="record.status == 1">解析</view>
+					<view class="btn" @click="questionReport(record)" v-if="record.status == 1">报告</view>
+					<view class="btn continue" @click="doContinue(record,index)" v-if="record.status == 0 && record.historyExamJson">继续答题</view>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+export default {
+	data() {
+		return {
+			index: 0,
+			list: [],
+			list1: [],
+			recordList: [],
+			goodsData: {},
+			param: {
+				moduleExamId:0,
+				chapterExamId:0,
+				examId:0,
+				goodsId:0,
+				pageNum: 1,
+				pageSize: 10
+			},
+			isRepeat:false,
+			total: 0,
+			activeIndex: 0,
+			typeIndex:0,
+			itemIndex:'',
+		};
+	},
+	onLoad(option) {
+		
+		this.param.moduleExamId = option.moduleId,
+		this.param.chapterExamId = option.chapterId,
+		this.param.examId = option.examId,
+		this.param.goodsId = option.goodsId,
+		this.getExamRecordList();
+	},
+	onPullDownRefresh() {
+		let that = this;
+		this.param = {
+			moduleExamId:this.param.moduleId,
+			chapterExamId:this.param.chapterId,
+			examId:this.param.examId,
+			goodsId:this.param.goodsId,
+			pageNum: 1,
+			pageSize: 10
+		};
+		this.getExamRecordList();
+		setTimeout(function() {
+			uni.stopPullDownRefresh();
+		}, 500);
+	},
+	onReachBottom() {
+		if (this.recordList.length < this.total) {
+			this.param.pageNum++;
+			this.getExamRecordList();
+		}
+	},
+	onShow() {
+		if(this.isRepeat) {
+			this.addRecord();
+		} else {
+			if(this.itemIndex !== '') {
+				this.refreshByIndex();
+			}
+		}
+		
+	},
+	methods: {
+		questionBankExplain(record) {
+			uni.navigateTo({
+				url:'/pages2/bank/questionBankExplain?id='+record.examId +'&goodsid='+record.goodsId+'&moduleId='+record.moduleExamId+'&chapterId='+record.chapterExamId+'&orderGoodsId='+record.orderGoodsId
+				
+			})
+		},
+		questionReport(record) {
+			uni.navigateTo({
+				url:'/pages2/bank/question_report?goodsId='+record.goodsId+'&chapterId='+record.chapterExamId+'&moduleId='+record.moduleExamId+'&examId='+record.examId+'&id=' + record.recordId+'&orderGoodsId='+record.orderGoodsId
+			})
+		},
+		addRecord() {
+			this.$api.examRecordList({
+				moduleExamId:this.param.moduleId,
+				chapterExamId:this.param.chapterId,
+				examId:this.param.examId,
+				goodsId:this.param.goodsId,
+				pageNum: 1,
+				pageSize: 1
+			}).then(res => {
+				this.recordList.unshift(res.data.rows[0])
+			});
+			this.isRepeat = false;
+		},
+		refreshByIndex() {
+			this.$api.examRecordGroupList({
+				moduleExamId:this.param.moduleId,
+				chapterExamId:this.param.chapterId,
+				examId:this.param.examId,
+				goodsId:this.param.goodsId,
+				pageNum: this.itemIndex+1,
+				pageSize: 1
+			}).then(res => {
+				this.$set(this.recordList,this.itemIndex,res.data.rows[0])
+				this.itemIndex = ''
+			});
+		},
+		getExamRecordList() {
+			if (this.param.pageNum == 1) {
+				this.recordList = [];
+			}
+			this.$api.examRecordList(this.param).then(res => {
+				this.recordList.push.apply(this.recordList, res.data.rows);
+				this.total = res.data.total;
+			});
+		},
+		/**
+		 * 继续做题
+		 */
+		doContinue(record,index) {
+			this.itemIndex = index;
+			this.isRepeat = false;
+			uni.navigateTo({
+				url:'/pages2/bank/questionBankContinue?recordId=' +
+						record.recordId +
+						'&id=' +
+						record.examId +
+						'&goodsid=' +
+						record.goodsId +
+						'&moduleId=' +
+						record.moduleExamId +
+						'&chapterId=' +
+						record.chapterExamId
+			})
+		},
+		/**
+		 * 去做题
+		 */
+		async doRepeat(id, goodsId, moduleId = 0, chapterId = 0,index) {
+			// await this.getDetail(goodsId);
+			this.itemIndex = '';
+			this.isRepeat = true;
+			let count = await this.examRecordCount(id,goodsId);
+			let answerNum = await this.getExamDetail(id);
+			//超过答题次数
+			if (answerNum > 0 && count >= answerNum) {
+				this.$u.toast('该试卷只能答题' + answerNum + '次!');
+				return;
+			}
+
+			uni.navigateTo({
+				url: '/pages2/bank/questionBank?id=' + id + '&goodsid=' + goodsId + '&moduleId=' + moduleId + '&chapterId=' + chapterId + ''
+			});
+		},
+		/**
+		 * @param {Object} exam_id
+		 * 获取试卷可以做的次数
+		 */
+		getExamDetail(exam_id) {
+			return new Promise(resolve => {
+				this.$api.getExamDetail(exam_id).then(res => {
+					resolve(res.data.data.answerNum);
+				});
+			});
+		},
+		/**
+		 * 查询试卷历史做题次数
+		 */
+		examRecordCount(examId,goodsId) {
+			return new Promise(resolve => {
+				this.$api
+					.examRecordCount({
+						examId: examId,
+						goodsId: goodsId
+					})
+					.then(res => {
+						resolve(res.data.data);
+					});
+			});
+		},
+
+		getDetail(id) {
+			return new Promise(resolve => {
+				this.$api.goodsDetail(id).then(res => {
+					this.goodsData = res.data.data;
+					resolve();
+				});
+			});
+		}
+	}
+};
+</script>
+<style>
+page {
+	background: #eaeef1;
+}
+</style>
+<style lang="scss" scope>
+	.animals{
+		transition: all 0.3s;
+		transform: rotate(180deg);
+	}
+
+.record {
+	padding: 16rpx 8rpx;
+	display: flex;
+	flex-wrap: wrap;
+	.item {
+		margin-bottom: 16rpx;
+		width:359rpx;
+		background: #ffffff;
+		border-radius: 16rpx;
+		padding: 65rpx 20rpx 22rpx;
+		position: relative;
+		overflow: hidden;
+		
+		&:nth-of-type(2n) {
+			margin-left:16rpx;
+			
+		}
+
+		.note {
+			color: #fff;
+			position: absolute;
+			left: 0;
+			top: 0;
+			// width: 112rpx;
+			padding: 0rpx 10rpx;
+			height: 40rpx;
+			text-align: center;
+			line-height: 40rpx;
+			background: linear-gradient(180deg, #4facfe, #007aff);
+			border-radius: 16rpx 0px 16rpx 0rpx;
+		}
+
+		.title {
+			font-size: 32rpx;
+			color: #333333;
+			font-weight: bold;
+		}
+
+		.desc {
+			margin-top: 26rpx;
+			view {
+				margin: 16rpx 0;
+
+				image {
+					width: 23rpx;
+					height: 24rpx;
+				}
+
+				text {
+					margin-left: 15rpx;
+					font-size: 24rpx;
+					color: #999999;
+					line-height: 36rpx;
+				}
+			}
+		}
+
+		.btns {
+			margin-top: 26rpx;
+			display: flex;
+			justify-content: space-around;
+			.btn {
+				flex:1;
+				margin:0 5rpx;
+				height: 48rpx;
+				line-height: 48rpx;
+				text-align: center;
+				color: #007aff;
+				background: #ffffff;
+				border: 1rpx solid #007aff;
+				border-radius: 16rpx;
+				
+				&.continue {
+					width:317rpx;
+				}
+			}
+		}
+	}
+}
+
+.modal {
+	bottom:0;
+	z-index: 199999999;
+	position: fixed;
+	left: 0;
+	width: 100%;
+
+	.content {
+		position: relative;
+		z-index: 10;
+		background: #fff;
+		padding: 8rpx 12rpx 20rpx;
+		display: flex;
+		flex-wrap: wrap;
+
+		.top {
+			margin: 0 auto;
+			width: 726rpx;
+			height: 80rpx;
+			background: #f5f5f5;
+			color: #666666;
+			border-radius: 16rpx;
+			text-align: center;
+			line-height: 80rpx;
+			font-size: 32rpx;
+		}
+
+		.list {
+			width:100%;
+			margin-top: 16rpx;
+			display: flex;
+			flex-wrap: wrap;
+			justify-content: space-between;
+
+			.item {
+				padding: 25rpx 20rpx;
+				width: 49%;
+				background: #f5f5f5;
+				border-radius: 16rpx;
+				font-size: 32rpx;
+				color: #666666;
+				margin: 8rpx 0;
+			}
+		}
+	}
+
+	.modal_wrap {
+		position: absolute;
+		left: 0;
+		width: 100%;
+		top: 0;
+		height: 100%;
+		background: rgba(0, 0, 0, 0.3);
+	}
+}
+.activesty {
+	background: #007aff !important;
+	color: #fff !important;
+}
+</style>

+ 357 - 0
pages3/imgCompare/index.vue

@@ -0,0 +1,357 @@
+<template>
+	<view>
+		<nav-bar title="身份证"></nav-bar>
+		<div class="camera-wrap">
+			<camera ref="camera" resolution="high" class="camera" frame-size="small"  device-position="back" flash="off"  @error="error"></camera>
+			<image class="avatar" :src="face ? '../static/avatar.png' : '../static/back.png' "></image>
+		</div>
+		<canvas class="canvas"  canvas-id="canvas1"></canvas>
+		<canvas class="canvas"  canvas-id="canvas"></canvas>
+		<view>精度{{point}}</view>
+		<view>人脸面符合次数{{frontIsCard}}</view>
+		<view>国徽面合次数{{backIsCard}}</view>
+		<!-- <image class="img" :src="src" mode="widthFix"></image> -->
+		<button @click="takePhoto(true)">人脸面</button>
+		<button @click="takePhoto(false)">国徽面</button>
+	</view>
+</template>
+
+<script>
+import { mapGetters } from 'vuex';
+import { templateFront, templateBack } from '../../common/isCardTemplate.js'
+export default {
+	data() {
+		return {
+			face:true,
+			point:0,
+			context:null,
+			src:"",
+			isCompare:false,
+			frontIsCard:0,
+			backIsCard:0,
+			frontData:templateFront, //身份证人脸面模板特征值
+			backData:templateBack  //身份证国徽面模板特征值
+		};
+	},
+	computed: { ...mapGetters(['userInfo','goodsAuditionConfigIdList','playSectionId']) },
+	onLoad(option) {
+		
+	},
+	onUnload(option) {
+		
+	},
+	mounted() {
+		
+		this.context = uni.createCanvasContext('canvas')
+		const ctx = uni.createCameraContext();
+		const listener = ctx.onCameraFrame(frame => {
+			if(!this.isCompare) {
+				this.isCompare = true;
+				
+				uni.getSystemInfo({
+				  success: (res) => { // res - 各种参数
+				
+				      let info = uni.createSelectorQuery().select(".canvas");
+				      info.boundingClientRect((data1) => { //data - 各种参数
+							var buffer = new Uint8ClampedArray(frame.data);
+							//获取是实时拍照原图
+							uni.canvasPutImageData({
+								  canvasId: 'canvas',
+								  x: 0,
+								  y: 0,
+								  width: frame.width,
+								  height: frame.height,
+								  data: buffer,
+								  success:(res) => {
+									  //生成图片
+									  uni.canvasToTempFilePath({
+									    quality:1,
+									    x: 0,
+									    y: 0,
+									    width: frame.width,
+									    height: frame.height,
+										destWidth:data1.width,
+										destHeight:data1.height,
+									    canvasId: 'canvas',
+									    success: (res) => {
+											// 在H5平台下,tempFilePath 为 base64
+											
+											//绘制原图到canvas上
+											
+											this.context.drawImage(res.tempFilePath,0,0,data1.width,data1.height)
+											this.context.draw();
+										  
+											let avatarInfo = uni.createSelectorQuery().select(".avatar");
+											
+											//获取原图扫描框大小
+											avatarInfo.boundingClientRect((data) => {  
+												// //data - 各种参数
+												let left = data.left;
+												let top = data.top;
+												let width = data.width;
+												let height = data.height;
+												
+												//获取原图扫描框内容
+												uni.canvasGetImageData({
+												  canvasId: 'canvas',
+												  x: left,
+												  y: top,
+												  width: width,
+												  height: height,
+												  success:(res) => {
+													// this.isCompare = false;
+													  
+													  
+														//绘制扫描图片
+													    uni.canvasPutImageData({
+															canvasId: 'canvas',
+															x: 0,
+															y: 0,
+															width: width,
+															height: height,
+															data: res.data,
+															success:(res) => {
+													  		  //生成图片
+													  		    uni.canvasToTempFilePath({
+																  quality:1,
+													  		      x: 0,
+													  		      y: 0,
+																  destWidth:width,
+																  destHeight:height,
+													  		      width: width,
+													  		      height: height,
+													  		      canvasId: 'canvas',
+													  		      success:async  (res1) => {
+													  		  		//绘制并压缩
+																	
+													  		  		this.context.drawImage(res1.tempFilePath,0,0,width,height,0,0,200,200)
+													  		  		this.context.draw();
+																	
+																		let res = await this.canvasGetImageData('canvas');
+																		let newData = Array(res.data.length)
+																		newData.fill(0)  
+																		res.data.forEach((_data, index) => {  
+																		  if ((index + 1) % 4 === 0) {  
+																			const R = res.data[index - 3]  
+																			const G = res.data[index - 2]  
+																			const B = res.data[index - 1] 
+																			const gray = ~~((R + G + B) / 3)  
+																			
+																			res.data[index - 3] = gray  
+																			res.data[index - 2] = gray  
+																			res.data[index - 1] = gray 
+																			res.data[index] = 255 // Alpha 值固定为255  
+																		  }  
+																		})
+																		uni.canvasPutImageData({
+																			canvasId: 'canvas1',
+																			x: 0,
+																			y: 0,
+																			width: res.width,
+																			height: res.height,
+																			data: res.data,
+																			success:(res) => {
+																				// this.isCompare = false;
+																				uni.canvasToTempFilePath({
+																					destWidth:res.width,
+																					destHeight:res.height,
+																					quality:1,
+																				  x: 0,
+																				  y: 0,
+																				  width: width,
+																				  height: height,
+																				  canvasId: 'canvas1',
+																				  success: (res2) => {
+																					  this.src = res2.tempFilePath
+																				  },
+																				})
+																			},
+																			fail:err => {
+																				console.log(err,'err')
+																			}
+																		})
+																		
+																		
+																		
+																		// for (let i = 0; i < newData.length; i += 4) {  
+																		//   let R = newData[i]  
+																		//   let G = newData[i + 1]  
+																		//   let B = newData[i + 2]  
+																		//   let Alpha = newData[i + 3] 
+																		// }  
+																		let getData = this.getHashFingerprint(res)
+																		let similarty = this.cosineSimilarity(this.face ? this.frontData : this.backData,getData)
+																		// let distance = this.hammingDistance(this.frontData,result)
+																		// let similarty =  (this.frontData.length - distance) / this.frontData.length
+																		if(similarty >= 0.8) {
+																			this.src = res1.tempFilePath
+																			if(this.face) {
+																				this.frontIsCard++;
+																			} else {
+																				this.backIsCard++;
+																			}
+																			
+																		} 
+																		
+																		this.point = similarty
+																		
+																		setTimeout(() => {
+																			this.isCompare = false;
+																		},200)
+																		console.log(similarty,'similarty')
+																			
+													  		  	},
+													  		  })
+															},
+														})
+													  
+													  
+													  
+													  
+													  
+														
+													    
+													}
+												})
+											}).exec()
+											  
+										 }
+										 
+									  })
+								  },
+								  fail(err) {
+									  console.log(err)
+								  }
+							})
+				      }).exec()
+					   }
+				});
+				
+				
+				
+			}
+		})
+		
+		listener.start()
+	},
+	methods: {
+		error(err) {
+			console.log(err)
+		},
+		
+		canvasGetImageData(id) {
+			return new Promise(resolve => {
+				uni.canvasGetImageData({
+					canvasId: id,
+					x: 0,
+					y: 0,
+					width: 200,
+					height: 200,
+					success:(res) => {
+						resolve(res)
+					},
+				})
+			})
+			
+		},
+		
+		hammingDistance (str1, str2) {  
+		  let distance = 0  
+		  const str1str1Arr = str1.split('')  
+		  const str2str2Arr = str2.split('')  
+		  str1str1Arr.forEach((letter, index) => {  
+		    if (letter !== str2str2Arr[index]) {  
+		      distance++  
+		    }  
+		  })  
+		  return distance  
+		} ,
+		
+		cosineSimilarity (sampleFingerprint, targetFingerprint) {  
+		  // cosθ = ∑n, i=1(Ai × Bi) / (√∑n, i=1(Ai)^2) × (√∑n, i=1(Bi)^2) = A · B / |A| × |B|  
+		  const length = sampleFingerprint.length  
+		  let innerProduct = 0  
+		  for (let i = 0; i < length; i++) {  
+		    innerProduct += sampleFingerprint[i] * targetFingerprint[i]  
+		  }  
+		  let vecA = 0  
+		  let vecB = 0  
+		  for (let i = 0; i < length; i++) {  
+		    vecA += sampleFingerprint[i] ** 2  
+		    vecB += targetFingerprint[i] ** 2  
+		  }  
+		  const outerProduct = Math.sqrt(vecA) * Math.sqrt(vecB)  
+		  return innerProduct / outerProduct  
+		} ,
+		
+		
+		
+		getHashFingerprint (imgData) {  
+		  const grayList = imgData.data.reduce((pre, cur, index) => {  
+		    if ((index + 1) % 4 === 0) {  
+		      pre.push(imgData.data[index - 1])  
+		    }  
+		    return pre  
+		  }, [])  
+		  const length = grayList.length  
+		  const grayAverage = grayList.reduce((pre, next) => (pre + next), 0) / length  
+		  return grayList.map(gray => (gray >= grayAverage ? 1 : 0)).join('')  
+		} ,
+		
+		
+		takePhoto(bo) {
+			this.face = bo
+			// const ctx = uni.createCameraContext();
+			// ctx.takePhoto({
+			// 	quality: 'high',
+			// 	success: res => {
+			// 		this.src = res.tempImagePath;
+			// 	},
+			// 	fail: err => {
+			// 		console.log(err);
+			// 	}
+			// });
+		}
+	}
+};
+</script>
+<style >
+	page{
+		background-color: #EAEEF1;
+	}
+</style>
+<style scope lang="scss">
+	.camera-wrap {
+		position: relative;
+		
+		.camera {
+			width: 750rpx;
+			height: 916.67rpx;
+		}
+		
+		.avatar {
+			opacity: 0.3;
+			position:absolute;
+			left:50%;
+			top:40rpx;
+			transform: translateX(-50%);
+			width:633rpx;
+			height:400rpx;
+		}
+	}
+	
+	.canvas {
+		position:fixed;
+		top:9999999%;
+		left:9999999%;  //canvas藏起来
+		width: 750rpx;
+		height: 916.67rpx;
+	}
+	
+	.img {
+		display: block;
+		margin:0 auto;
+		width:633rpx;
+		height:400rpx;
+	}
+</style>

BIN
pages3/static/avatar.png


BIN
pages3/static/back.png


BIN
static/logo_xcx.png


Некоторые файлы не были показаны из-за большого количества измененных файлов