|
|
@@ -0,0 +1,505 @@
|
|
|
+<template>
|
|
|
+ <view class="content">
|
|
|
+ <!-- 拍照区域 -->
|
|
|
+ <view class="cameraField">
|
|
|
+ <!-- 上传的人脸图片 -->
|
|
|
+ <canvas
|
|
|
+ canvas-id="canvas"
|
|
|
+ id="canvas"
|
|
|
+ type="2d"
|
|
|
+ style="width: 100%; height: 100%"
|
|
|
+ ></canvas>
|
|
|
+ <!-- 提示框 -->
|
|
|
+ <view class="hint" v-if="isShow3">
|
|
|
+ <image :src="hintImage" />
|
|
|
+ {{ hintWord }}
|
|
|
+ </view>
|
|
|
+ <!-- “上传中”提示框 -->
|
|
|
+ <view class="uploading" v-if="isShow4">
|
|
|
+ <image src="../../static/images/等待@2x.png" mode="scaleToFill" />
|
|
|
+ <text>人脸匹配中...</text>
|
|
|
+ </view>
|
|
|
+ <!-- 头像限制框 -->
|
|
|
+ <image
|
|
|
+ class="head"
|
|
|
+ src="../../static/images/head1.png"
|
|
|
+ mode="scaleToFill"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ <!-- 控件区域 -->
|
|
|
+ <view class="controlField">
|
|
|
+ <!-- 拍照控件 -->
|
|
|
+ <view class="control1" v-if="isShow1">
|
|
|
+ <view>
|
|
|
+ <image class="light" src="../../static/images/light.png" />
|
|
|
+ </view>
|
|
|
+ <view @click="takePhoto()">
|
|
|
+ <image class="take" src="../../static/images/take.png" />
|
|
|
+ </view>
|
|
|
+ <view>
|
|
|
+ <image class="change" src="../../static/images/change.png" />
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <!-- 重拍/上传控件 -->
|
|
|
+ <view class="control2" v-if="isShow2">
|
|
|
+ <view @click="resetPhoto">重拍</view>
|
|
|
+ <view @click="upload">使用照片</view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script></script>
|
|
|
+<script>
|
|
|
+import { EXIF } from "../../node_modules/exif-js/exif";
|
|
|
+import { mapState, mapMutations } from "vuex";
|
|
|
+import {
|
|
|
+ pathToBase64,
|
|
|
+ base64ToPath,
|
|
|
+} from "../../js_sdk/mmmm-image-tools/index.js";
|
|
|
+export default {
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ isShow1: true, //拍照控件
|
|
|
+ isShow2: false, //重拍/上传控件
|
|
|
+ isShow3: true, //提示框
|
|
|
+ isShow4: false, //“上传中”提示框
|
|
|
+ hintImage: "../../static/images/注意@2x.png", //提示图标
|
|
|
+ hintWord: "请勿遮挡面部", //提示文字
|
|
|
+ imgPath: "", //上传的人脸图片
|
|
|
+ baseStr: "",
|
|
|
+ tipFlag: "",
|
|
|
+ maxWidth: "",
|
|
|
+ maxHeight: "",
|
|
|
+ };
|
|
|
+ },
|
|
|
+ computed: mapState(["position", "userData"]),
|
|
|
+
|
|
|
+ onLoad(options) {
|
|
|
+ //拉取微信授权
|
|
|
+ this.loginFilter();
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ let that = this;
|
|
|
+ (function () {
|
|
|
+ var u = navigator.userAgent;
|
|
|
+ var isAndroid = u.indexOf("Android") > -1 || u.indexOf("Linux") > -1; //android终端或者uc浏览器
|
|
|
+ var isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端
|
|
|
+ if (isiOS) {
|
|
|
+ that.tipFlag = "ios";
|
|
|
+ }
|
|
|
+ if (isAndroid) {
|
|
|
+ that.tipFlag = "Android";
|
|
|
+ }
|
|
|
+ })();
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ ...mapMutations(["getPosition", "getUserData"]),
|
|
|
+ // 授权获取信息
|
|
|
+ loginFilter() {
|
|
|
+ let cardNumber = this.getQueryString("cardNumber");
|
|
|
+ let name = this.getQueryString("name");
|
|
|
+ let error = this.getQueryString("error");
|
|
|
+ let homeWeb =
|
|
|
+ "https://open.wecard.qq.com/connect/oauth/authorize?app_key=8C41E2FECF2E9925&response_type=code&scope=snsapi_userinfo&ocode=1015730314&redirect_uri=https://jtishfw.ncjti.edu.cn/yinxin/ncjtSecurityManagement/getUserInfo&state=1";
|
|
|
+ if (!cardNumber) {
|
|
|
+ window.location.href = homeWeb;
|
|
|
+ } else {
|
|
|
+ if (error) {
|
|
|
+ uni.showToast({
|
|
|
+ title: "服务器连接失败",
|
|
|
+ icon: "error",
|
|
|
+ mask: true,
|
|
|
+ duration: 3000,
|
|
|
+ });
|
|
|
+ setTimeout(function () {
|
|
|
+ uni.navigateTo({
|
|
|
+ url: "../index/index",
|
|
|
+ });
|
|
|
+ }, 1000);
|
|
|
+ }
|
|
|
+ this.$store.state.name = name;
|
|
|
+ this.$store.state.idnum = cardNumber;
|
|
|
+ this.judgeGrade();
|
|
|
+ this.judgeWrite();
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ //判断老生无权限
|
|
|
+ judgeGrade() {
|
|
|
+ var date = new Date();
|
|
|
+ var year = date.getFullYear().toString();
|
|
|
+ let grade = this.getQueryString("grade");
|
|
|
+ if (grade == year) {
|
|
|
+ return;
|
|
|
+ } else {
|
|
|
+ uni.showToast({
|
|
|
+ title: "无权限,仅对新生请退出",
|
|
|
+ icon: "error",
|
|
|
+ mask: true,
|
|
|
+ duration: 50000,
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ //判断是否填写问卷
|
|
|
+ judgeWrite() {
|
|
|
+ uni.request({
|
|
|
+ url: "https://jtishfw.ncjti.edu.cn/yinxin/ncjtSecurityManagement/freshmanSurveyDoneByIdnum",
|
|
|
+ data: {
|
|
|
+ idnum: this.$store.state.idnum,
|
|
|
+ },
|
|
|
+ header: {
|
|
|
+ Accept: "application/json",
|
|
|
+ "Content-Type": "application/json",
|
|
|
+ "X-Requested-With": "XMLHttpRequest",
|
|
|
+ },
|
|
|
+ method: "GET",
|
|
|
+ sslVerify: true,
|
|
|
+ success: ({ data, statusCode, header }) => {
|
|
|
+ console.log(data);
|
|
|
+ if (data.result === "success") {
|
|
|
+ uni.navigateTo({
|
|
|
+ url: "../index/index",
|
|
|
+ });
|
|
|
+ }
|
|
|
+ },
|
|
|
+ fail: (error) => {},
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ //获取当前URL指定参数
|
|
|
+ getQueryString(name) {
|
|
|
+ let url = window.location.href; // 获取URL
|
|
|
+
|
|
|
+ let pattern = new RegExp("[\?\&]" + name + "=([^\&]+)", "i"); // 正则匹配URL
|
|
|
+
|
|
|
+ let matcher = pattern.exec(url);
|
|
|
+
|
|
|
+ if (matcher == null || matcher.length < 1) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return decodeURIComponent(matcher[1]); // 输出指定的参数值 中文也可以
|
|
|
+ },
|
|
|
+
|
|
|
+ //拍照
|
|
|
+ takePhoto() {
|
|
|
+ if (this.isShow4) {
|
|
|
+ this.isShow3 = !this.isShow3;
|
|
|
+ this.isShow4 = !this.isShow4;
|
|
|
+ this.isShow1 = !this.isShow1;
|
|
|
+ this.isShow2 = !this.isShow2;
|
|
|
+ } else {
|
|
|
+ this.isShow1 = !this.isShow1;
|
|
|
+ this.isShow2 = !this.isShow2;
|
|
|
+ }
|
|
|
+ this.photo();
|
|
|
+ },
|
|
|
+
|
|
|
+ //重拍
|
|
|
+ resetPhoto() {
|
|
|
+ if (this.isShow4) {
|
|
|
+ this.isShow3 = !this.isShow3;
|
|
|
+ this.isShow4 = !this.isShow4;
|
|
|
+ this.isShow1 = !this.isShow1;
|
|
|
+ this.isShow2 = !this.isShow2;
|
|
|
+ }
|
|
|
+ this.photo();
|
|
|
+ },
|
|
|
+
|
|
|
+ //压缩上传的图片
|
|
|
+ compressUploadImg(img, width, height, ratio) {
|
|
|
+ // img可以是dataURL或者图片url
|
|
|
+ let canvas = document.createElement("canvas");
|
|
|
+ canvas.width = width;
|
|
|
+ canvas.height = height;
|
|
|
+ let ctx = canvas.getContext("2d");
|
|
|
+ let img64 = canvas.toDataURL("image/jpeg", ratio);
|
|
|
+ console.log(img64);
|
|
|
+ return (this.$store.state.imageBase = img64); // 压缩后的base64串
|
|
|
+ },
|
|
|
+
|
|
|
+ //安卓机图片修正
|
|
|
+ async detail(url) {
|
|
|
+ let maxWidth = this.maxWidth;
|
|
|
+ let Orientation = 1;
|
|
|
+ //获取图片META信息
|
|
|
+ await this.getImageTag(url, "Orientation", function (e) {
|
|
|
+ if (e != undefined) Orientation = e;
|
|
|
+ });
|
|
|
+ var img = null;
|
|
|
+ var canvas = null;
|
|
|
+ await this.comprossImage(url, maxWidth, function (e) {
|
|
|
+ img = e.img;
|
|
|
+ canvas = e.canvas;
|
|
|
+ });
|
|
|
+ // console.log(Orientation,"Orientation")
|
|
|
+ let baseStr = "";
|
|
|
+ //如果方向角不为1,都需要进行旋转
|
|
|
+ switch (Orientation) {
|
|
|
+ case 6: //需要顺时针(向右)90度旋转
|
|
|
+ baseStr = this.rotateImg(img, "right", canvas);
|
|
|
+ break;
|
|
|
+ case 8: //需要逆时针(向左)90度旋转
|
|
|
+ baseStr = this.rotateImg(img, "left", canvas);
|
|
|
+ break;
|
|
|
+ case 3: //需要180度旋转 转两次
|
|
|
+ baseStr = this.rotateImg(img, "right", canvas, 2);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ baseStr = this.rotateImg(img, "", canvas);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ // console.log(baseStr, "baseStr");
|
|
|
+ },
|
|
|
+ async comprossImage(imgSrc, maxWidth, func) {
|
|
|
+ if (!imgSrc) return 0;
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ uni.getImageInfo({
|
|
|
+ src: imgSrc,
|
|
|
+ success(res) {
|
|
|
+ let img = new Image();
|
|
|
+ img.src = res.path;
|
|
|
+ // console.log(img);
|
|
|
+ let canvas = uni.createCanvasContext("canvas");
|
|
|
+ let obj = new Object();
|
|
|
+ obj.img = img;
|
|
|
+ obj.canvas = canvas;
|
|
|
+ resolve(func(obj));
|
|
|
+ let fileObj = document.createElement("file"); //上传文件的对象
|
|
|
+ },
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+ getImageTag(file, tag, suc) {
|
|
|
+ if (!file) return 0;
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ /* eslint-disable func-names */
|
|
|
+ // 箭头函数会修改this,所以这里不能用箭头函数
|
|
|
+ let imgObj = new Image();
|
|
|
+ imgObj.src = file;
|
|
|
+ // console.log(imgObj);
|
|
|
+ uni.getImageInfo({
|
|
|
+ src: file,
|
|
|
+ success(res) {
|
|
|
+ EXIF.getData(imgObj, function () {
|
|
|
+ EXIF.getAllTags(this);
|
|
|
+ let or = EXIF.getTag(this, "Orientation"); //这个Orientation 就是我们判断需不需要旋转的值了,有1、3、6、8
|
|
|
+ resolve(suc(or));
|
|
|
+ });
|
|
|
+ },
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+ rotateImg(img, direction, canvas, times = 1) {
|
|
|
+ console.log("开始旋转");
|
|
|
+ //最小与最大旋转方向,图片旋转4次后回到原方向
|
|
|
+ var min_step = 0;
|
|
|
+ var max_step = 3;
|
|
|
+ if (img == null) return;
|
|
|
+ //img的高度和宽度不能在img元素隐藏后获取,否则会出错
|
|
|
+ var height = img.height;
|
|
|
+ var width = img.width;
|
|
|
+ let maxWidth = this.maxWidth;
|
|
|
+ let maxHeight = this.maxHeight;
|
|
|
+ var step = 0;
|
|
|
+ if (step == null) {
|
|
|
+ step = min_step;
|
|
|
+ }
|
|
|
+ if (direction == "right") {
|
|
|
+ step += times;
|
|
|
+ //旋转到原位置,即超过最大值
|
|
|
+ step > max_step && (step = min_step);
|
|
|
+ } else if (direction == "left") {
|
|
|
+ step -= times;
|
|
|
+ step < min_step && (step = max_step);
|
|
|
+ } else {
|
|
|
+ //不旋转
|
|
|
+ step = 0;
|
|
|
+ }
|
|
|
+ //旋转角度以弧度值为参数
|
|
|
+ var degree = (step * 90 * Math.PI) / 180;
|
|
|
+ var ctx = uni.createCanvasContext("canvas");
|
|
|
+ // var ctx = canvas.getContext("2d");
|
|
|
+ // console.log(degree);
|
|
|
+ // console.log(step);
|
|
|
+ switch (step) {
|
|
|
+ case 1:
|
|
|
+ // console.log("右旋转 90度");
|
|
|
+ width = maxHeight;
|
|
|
+ height = maxWidth;
|
|
|
+ ctx.rotate(degree);
|
|
|
+ ctx.drawImage(img.src, 0, -height, width, height);
|
|
|
+ ctx.draw();
|
|
|
+ break;
|
|
|
+ case 2:
|
|
|
+ //console.log('旋转 180度')
|
|
|
+ width = maxWidth;
|
|
|
+ height = maxHeight;
|
|
|
+ ctx.rotate(degree);
|
|
|
+ ctx.drawImage(img.src, -width, -height, width, height);
|
|
|
+ ctx.draw();
|
|
|
+ break;
|
|
|
+ case 3:
|
|
|
+ // console.log("左旋转 90度");
|
|
|
+ width = maxHeight;
|
|
|
+ height = maxWidth;
|
|
|
+ ctx.rotate(degree);
|
|
|
+ ctx.drawImage(img.src, -width, 0, width, height);
|
|
|
+ ctx.draw();
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ //不旋转
|
|
|
+ // canvas.width = width;
|
|
|
+ // canvas.height = height;
|
|
|
+ width = maxWidth;
|
|
|
+ height = maxHeight;
|
|
|
+ ctx.drawImage(img.src, 0, 0, width, height);
|
|
|
+ ctx.draw();
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ // let baseStr = canvas.toDataURL("image/jpeg", 1);
|
|
|
+ // let baseStr = this.$store.state.imageBase;
|
|
|
+ // return baseStr;
|
|
|
+ },
|
|
|
+
|
|
|
+ //照片
|
|
|
+ photo() {
|
|
|
+ if (this.$store.state.idnum) {
|
|
|
+ let that = this;
|
|
|
+ uni.chooseImage({
|
|
|
+ count: 1,
|
|
|
+ sourceType: ["camera"],
|
|
|
+ sizeType: ["compressed"],
|
|
|
+ success: (res) => {
|
|
|
+ uni.getSystemInfo({
|
|
|
+ success: function (res2) {
|
|
|
+ that.maxWidth = res2.windowWidth;
|
|
|
+ let base = 4 / 3;
|
|
|
+ that.maxHeight = that.maxWidth * base;
|
|
|
+ },
|
|
|
+ });
|
|
|
+ that.imgPath = res.tempFilePaths[0]; //这就是要的blod
|
|
|
+ //上传压缩图片
|
|
|
+ // that.toBase64(that.imgPath);
|
|
|
+ that.compressUploadImg(
|
|
|
+ that.imgPath,
|
|
|
+ that.maxWidth,
|
|
|
+ that.maxHeight,
|
|
|
+ 1
|
|
|
+ );
|
|
|
+ //图片页面显示
|
|
|
+ if (that.tipFlag == "ios") {
|
|
|
+ let canvas = uni.createCanvasContext("canvas");
|
|
|
+ canvas.drawImage(
|
|
|
+ that.imgPath,
|
|
|
+ 0,
|
|
|
+ 0,
|
|
|
+ that.maxWidth,
|
|
|
+ that.maxHeight
|
|
|
+ );
|
|
|
+ canvas.draw();
|
|
|
+ } else {
|
|
|
+ that.detail(that.imgPath);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ complete: () => {
|
|
|
+ if (that.imgPath == null) {
|
|
|
+ this.isShow1 = !this.isShow1;
|
|
|
+ this.isShow2 = !this.isShow2;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ uni.showToast({
|
|
|
+ title: "请下拉刷新授权",
|
|
|
+ icon: "error",
|
|
|
+ mask: true,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ //上传图片
|
|
|
+ upload() {
|
|
|
+ this.isShow3 = !this.isShow3;
|
|
|
+ this.isShow4 = !this.isShow4;
|
|
|
+ uni.request({
|
|
|
+ url: "https://jtishfw.ncjti.edu.cn/yinxin/ncjtSecurityManagement/verifyBase64ImagesWithIDNumber",
|
|
|
+ data: {
|
|
|
+ idnum: this.$store.state.idnum,
|
|
|
+ image: this.$store.state.imageBase,
|
|
|
+ },
|
|
|
+ header: { "content-type": "application/x-www-form-urlencoded" },
|
|
|
+ method: "POST",
|
|
|
+ sslVerify: true,
|
|
|
+ success: ({ data, statusCode, header }) => {
|
|
|
+ if (data.error) {
|
|
|
+ this.isShow3 = !this.isShow3;
|
|
|
+ this.isShow4 = !this.isShow4;
|
|
|
+ uni.showToast({
|
|
|
+ title: "人脸匹配失败",
|
|
|
+ icon: "error",
|
|
|
+ mask: true,
|
|
|
+ duration: 3000,
|
|
|
+ });
|
|
|
+ setTimeout(this.back, 1000);
|
|
|
+ } else {
|
|
|
+ this.$store.state.sex = data.sex;
|
|
|
+ this.$store.state.examNumber = data.examNumber;
|
|
|
+ setTimeout(this.uploadSucceed, 500);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ fail: (error) => {
|
|
|
+ this.isShow3 = !this.isShow3;
|
|
|
+ this.isShow4 = !this.isShow4;
|
|
|
+ uni.showToast({
|
|
|
+ title: "上传失败",
|
|
|
+ icon: "error",
|
|
|
+ mask: true,
|
|
|
+ duration: 3000,
|
|
|
+ });
|
|
|
+ setTimeout(this.back, 2000);
|
|
|
+ },
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ //人脸采集成功
|
|
|
+ uploadSucceed() {
|
|
|
+ this.hintWord = "人脸采集成功";
|
|
|
+ this.hintImage = "../../static/images/成功@2x.png";
|
|
|
+ this.isShow3 = !this.isShow3;
|
|
|
+ this.isShow4 = !this.isShow4;
|
|
|
+ this.isShow2 = !this.isShow2;
|
|
|
+ setTimeout(this.navigateToConfirm, 2000);
|
|
|
+ },
|
|
|
+
|
|
|
+ //图片转Base64
|
|
|
+ toBase64(path) {
|
|
|
+ pathToBase64(path)
|
|
|
+ .then((base64) => {
|
|
|
+ this.$store.state.imageBase = base64;
|
|
|
+ })
|
|
|
+ .catch((error) => {
|
|
|
+ console.error(error);
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ //跳转人脸采集确认页面
|
|
|
+ navigateToConfirm() {
|
|
|
+ uni.navigateTo({
|
|
|
+ url: "../confirm/confirm",
|
|
|
+ });
|
|
|
+ },
|
|
|
+ back() {
|
|
|
+ uni.reLaunch({
|
|
|
+ url: "../faceSearch/faceSea",
|
|
|
+ });
|
|
|
+ },
|
|
|
+ },
|
|
|
+};
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss">
|
|
|
+@import url("./css/faceSea.min.css");
|
|
|
+</style>
|