caichengyu 9 månader sedan
förälder
incheckning
1cbfde1f88

+ 20 - 4
App.vue

@@ -1,5 +1,6 @@
 <script>
 	import plv from "./pages3/static/polyv-sdk/index";
+	import config from "./common/config.js";
 	export default {
 		onLaunch: function(option) {
 			uni.hideTabBar();
@@ -7,13 +8,28 @@
 			if (inviteCode && inviteCode != "") {
 				uni.setStorageSync("inviteCode", inviteCode);
 			}
-			plv.setApp({
-				apiId: "ezl5uy4zei",
-				apiSecret: "2bf5bb3c31d34531943df10284edd50b",
-			});
+			this.getApiData();
+
 			this.$store.dispatch("getConfig");
 		},
 		methods: {
+			getApiData() {
+				const url = config.BASE_URL + '/app/common/get/plv/info'; // 例如 'https://api.example.com/data'
+				uni.request({
+					url: url,
+					method: 'GET', // 根据需要可以是 'POST', 'PUT' 等
+					success: (res) => {
+						// console.log('获取数据成功:', res.data.data.apiId);
+						plv.setApp({
+							apiId: res.data.data.apiId,
+							apiSecret: res.data.data.apiSecret
+						});
+					},
+					fail: (err) => {
+						console.error('获取数据失败:', err);
+					}
+				});
+			}
 		},
 		onShow: function(option) {
 			this.$store.commit("setScene", option.scene || 0);

+ 2 - 1
common/config.js

@@ -1,7 +1,8 @@
 // test 测试环境
 const test = {
-	BASE_URL: "https://testapi.xyyxt.net",
+	// BASE_URL: "https://testapi.xyyxt.net",
 	// BASE_URL: "http://120.79.166.78:19012",
+	BASE_URL: "http://192.168.1.123:5055",
 	BASE_IMG_URL: "https://file-dev.xyyxt.net/",
 	domain: "h.xyyxt.net",
 	tenantId: "867735392558919680", //详粤云学堂

+ 10 - 3
common/httpList/course.js

@@ -193,14 +193,14 @@ export default {
 			data: data,
 		});
 	},
-	
+
 	orderGetViewSign(data) {
 		return myRequest({
-			url: "/order/getViewSign/"+data,
+			url: "/order/getViewSign/" + data,
 			method: "get",
 		});
 	},
-	
+
 	courseSkipPort(data) {
 		return myRequest({
 			url: "/course/skipPort",
@@ -286,4 +286,11 @@ export default {
 			method: "get",
 		});
 	},
+	resetSection(data) {
+		return myRequest({
+			url: '/study/record/reset/section',
+			method: 'post',
+			data: data
+		})
+	},
 };

+ 17 - 1
common/httpList/login.js

@@ -41,7 +41,14 @@ export default {
 			noToken: true,
 		});
 	},
-
+    check_gzh_openId(data) {
+		return myRequest({
+			url: "/app/common/check/gzh_openId",
+			method: "post",
+			data: data,
+			noToken: true,
+		});
+	},
 	//刷新令牌
 	refreshToken(data) {
 		return myRequest({
@@ -208,4 +215,13 @@ export default {
 			params: params
 		})
 	},
+	// 获取图形验证码
+	captchaImage(data) {
+		return myRequest({
+			url: "/captchaImage",
+			method: "get",
+			data: data,
+			noToken: true,
+		});
+	},
 };

+ 7 - 0
common/httpList/polyvVideo.js

@@ -16,4 +16,11 @@ export default {
 			method: 'get',
 		})
 	},
+	plvappidconfig(data) {
+		return myRequest({
+			url: '/app/common/get/plv/info',
+			method: 'get',
+			noToken: true
+		})
+	},
 }

+ 21 - 6
common/httpList/study.js

@@ -38,15 +38,30 @@ export default {
 			data: data
 		})
 	},
+	//保存当前视频节录像
+	courseTakeVideoRecord(data) {
+		return myRequest({
+			url: '/study/record/save/video',
+			method: 'post',
+			data: data
+		})
+	},
+	//查询当前视频节是否需要录像
+	getCheckTakeVideo(data) {
+		return myRequest({
+			url: '/study/record/check/video',
+			method: 'get',
+			data: data
+		})
+	},
 	//获取保利威视频信息详细信息
 	studyRecordGetChannelBasicInfo(data) {
 		return myRequest({
-				url: `/study/record/getChannelBasicInfo`,
-				method: 'get',
-				data:data
+			url: `/study/record/getChannelBasicInfo`,
+			method: 'get',
+			data: data
 		})
 	},
-	
-	
-}
 
+
+}

+ 8 - 0
common/httpList/userInfo.js

@@ -8,6 +8,14 @@ export default {
       data: data,
     });
   },
+  //修改客户端用户密码
+  appuserupdatePwd(data) {
+    return myRequest({
+      url: "/app/user/updatePwd",
+      method: "post",
+      data: data,
+    });
+  },
   // 修改用户活动邀请码
   shareActivityCode(data) {
     return myRequest({

+ 79 - 0
common/methodTool.js

@@ -342,6 +342,75 @@ export default {
 			})
 		});
 	},
+	//上传非图片文件H5
+	uploadFileH5(options, int,filetype) {
+		return new Promise((resolve, reject) => {
+			var self = this;
+			// #ifdef MP-WEIXIN
+			const isJPG =
+				options.indexOf("//tmp") !== -1 || options.indexOf("//temp") !== -1;
+			// #endif
+			// #ifdef H5
+			const isJPG = true;
+			// #endif
+			if (!isJPG) {
+				resolve(options);
+				return;
+			}
+			var data = {
+				imageStatus: int,
+			};
+			api.aliyunpolicy(data).then((res) => {
+				var ossToken = res.data.data.resultContent;
+				uni.uploadFile({
+					url: ossToken.host,
+					name: "file",
+					file: options,
+					fileType: filetype,
+					header: {
+						AuthorizationToken: "WX " + uni.getStorageSync("token"),
+					},
+					formData: {
+						key: ossToken.dir,
+						OSSAccessKeyId: ossToken.accessid,
+						policy: ossToken.policy,
+						Signature: ossToken.signature,
+						callback: ossToken.callback,
+						success_action_status: 200,
+					},
+					success: (result) => {
+						console.log(result);
+						result.data = result.data || '{}'
+						let jsonData = JSON.parse(result.data)
+						if (jsonData.resultContent && Number(jsonData.resultContent.size) >
+							0) {
+							resolve(ossToken.dir);
+						} else {
+							uni.showToast({
+								title: "上传接口报错",
+								icon: "none",
+							});
+							return;
+						}
+					},
+					fail: (error) => {
+						console.log("adsd",error);
+						uni.showToast({
+							title: "上传接口报错",
+							icon: "none",
+						});
+						return;
+					},
+				});
+			}).catch(err => {
+				uni.showToast({
+					title: "上传接口报错" + err,
+					icon: "none",
+				});
+				return;
+			})
+		});
+	},
 	getYears(strBirthday) {
 		if (!strBirthday) {
 			return "-";
@@ -677,6 +746,16 @@ export default {
 			return false;
 		}
 	},
+	isIPad() {
+	      const userAgent = navigator.userAgent || navigator.vendor || window.opera;
+	      return /iPad/.test(userAgent);
+	    },
+	isTablet() {
+	      const userAgent = navigator.userAgent || navigator.vendor || window.opera;
+		  const screenWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;// 判断是否是平板电脑
+          const isTablet = /Tablet/i.test(userAgent) || (screenWidth >= 768 && screenWidth < 1024);
+	      return isTablet;
+	    },
 	imageToBase64(url, quality = 0.8) {
 		return new Promise((resolve, reject) => {
 			url = this.splitImgHost(url);

+ 16 - 3
components/myPlayer2/tcPlayer.vue

@@ -85,7 +85,7 @@
 					playbackRate = JSON.parse(JSON.stringify(this.playbackRate));
 				}
 				const TCPlayer = window.TCPlayer;
-				console.log("腾讯视频是否自动播放", this.autoplay)
+				console.log("腾讯视频是否自动播放11111", this.autoplay)
 				console.log("腾讯视频是否允许拖拽进度条", this.progressControl) 
 				this.$api.tcVideoSign(this.fileId).then(async (res) => {
 							console.log("请求腾讯视频参数", res)
@@ -117,8 +117,10 @@
 										appID: res.data.data.appID,
 										psign: res.data.data.psign
 									});
+									setTimeout(() => {
 									tcPlayerContext.currentTime(
 										this.currentTime || 0);
+											}, 2000);
 								} else {
 									// 获取当前设备的信息
 									uni.getSystemInfo({
@@ -146,8 +148,7 @@
 										.getElementById("player2")
 										.insertAdjacentElement("afterend", player_tencent);
 									tcPlayerContext = TCPlayer("player-tencent", option);
-									tcPlayerContext.currentTime(
-										this.currentTime || 0);
+									
 									this.h5StateChange();
 								}
 							});
@@ -196,6 +197,7 @@
 							playing: "playing", // 视频初次播放或由暂停恢复播放时触发
 							ended: "ended", // 当前视频播放完毕时触发
 							error: "playerError", // 播放出现错误时触发
+							loadeddata:"loadeddata",//当前帧的数据已加载,但没有足够的数据来播放视频的下一帧时,触发该事件。
 						};
 						let that = this;
 						for (const key in states) {
@@ -207,10 +209,21 @@
 					},
 					// 新增用户视频学习日志
 					studyLog() {},
+					//
+					loadeddata(){
+						setTimeout(() => {
+						console.log("2s后调到"+this.currentTime);
+						//this.currentTime=300;
+															tcPlayerContext.currentTime(
+																this.currentTime || 0);//console.log("完成2s后调到"+this.currentTime);
+																}, 2000);
+					},
 					// 选定时间播放
 					seekVideo(time) {
 						time = time || 0;
+						setTimeout(() => {
 						tcPlayerContext.currentTime(time);
+						}, 1500);
 					},
 					// 重头播放
 					restart() {

+ 16 - 5
components/popup/camera.vue

@@ -109,6 +109,7 @@
 				showSet: false,
 				popupPhotoShow: false,
 				faceUrl: "",
+				stream:null,
 			};
 		},
 		methods: {
@@ -122,11 +123,11 @@
 				this.uploadLock = true;
 				let imgUrl = await this.imageInfos()
 				let compareFaceData = await this.faceRecognition(imgUrl);
-				if (compareFaceData >= 70) {
-					this.$emit("submitPhoto",imgUrl, compareFaceData);
+				if (compareFaceData.code === 200) {
+					this.$emit("submitPhoto",imgUrl, compareFaceData.data);
 				} else {
 					uni.showToast({
-						title: "人脸匹配不通过,请重新拍照上传",
+						title: compareFaceData.msg,
 						icon: "none",
 						duration: 2000,
 					});
@@ -196,6 +197,7 @@
 					window.navigator.webkitGetUserMedia ||
 					window.navigator.mozGetUserMedia
 				) {
+					this.stopCamera();
 					console.log("getUserMedia----");
 					// 调用用户媒体设备, 访问摄像头
 					this.getUserMedia({
@@ -334,7 +336,7 @@
 						},
 					});
 				}, 10 * 1000);
-
+                var _this=this;
 				this.$api
 					.faceCertificationCompareFace({
 						urlA: url,
@@ -345,7 +347,8 @@
 					.then((res) => {
 						clearTimeout(timer);
 						console.log(res, "人脸识别成功res");
-						resolve(res.data.data);
+						_this.stopCamera();
+						resolve(res.data);
 					})
 					.catch((err) => {
 						clearTimeout(timer);
@@ -371,6 +374,7 @@
 					const video = box.querySelector("video");
 					video.srcObject = stream;
 					video.play();
+					this.stream=stream;
 				});
 			},
 			photographError(err) {
@@ -408,6 +412,13 @@
 					window.navigator.getUserMedia(constraints, success, error);
 				}
 			},
+		   stopCamera() {
+			  if (this.stream) {
+			    this.stream.getVideoTracks().forEach(track => track.stop());
+				console.log('释放占用摄像头');
+			    this.stream = null;
+			  }
+			},
 		},
 		computed: {
 			params() {

+ 3 - 2
components/popup/index.vue

@@ -7,10 +7,11 @@
                 </view>
                 <view class="warn">温馨提示</view>
                 <view class="contents">
-                    <view class="words">1、请保证摄像头正对自己,避免头像偏左或者偏右。</view>
+                    <view class="words">1、请保证摄像头正对自己,避免头像偏左或者偏右。并离远一点拍照,肩膀要拍到。</view>
                     <view class="words">2、请保证拍照环境光线充足(照片太暗或曝光会降低验证通过率)。</view>
                     <view class="words">3、请保证整个头像在人脸识别区域内,脸部无遮挡装饰物(佩戴眼镜会降低通过率)。</view>
-                    <view class="words">4、如果下面视频中出现黑屏,摄像头可能被其他进程占用,请关闭其他调用摄像头的程序,重新刷新当前页面重新拍照识别。</view>
+                    <view class="words">4、拍照时不要开启背景虚化,保证背景清晰。</view>
+                    <view class="words">5、如果下面视频中出现黑屏,摄像头可能被其他进程占用,请关闭其他调用摄像头的程序,重新刷新当前页面重新拍照识别。</view>
                 </view>
                 <view class="take_photo" @click="toTakePhoto()">
                     去拍照

+ 678 - 0
components/popup/media.vue

@@ -0,0 +1,678 @@
+<template>
+	<view>
+		<u-popup v-model="isShow" mode="bottom" border-radius="40" :mask-close-able="false">
+			<view class="photoBox" v-if="isShow">
+				<view class="photoTop">
+					<view class="centersq">请正视手机屏幕</view>
+				</view>
+				<view class="photoCenter">
+					<view class="center_camera" v-if="isTaking">
+						<!-- #ifdef MP-WEIXIN -->
+						<camera device-position="front" flash="off" @error="error"
+							style="width: 400px; height: 400px;margin: 0 auto;">
+							<!-- 加人脸框 -->
+
+						</camera>
+						<!-- #endif -->
+						<!-- #ifdef H5 -->
+						<video :controls="false" v-show="status !== 3" id="video" width="400" height="400"
+							class="photo_v"></video>
+						<video id="video1" v-show="status === 3" class="photo_v2" autoplay controls :src="url"></video>
+						<view class="mask" v-if="false"></view>
+						<!-- #endif -->
+					</view>
+					<view class="custom" v-if="!isTaking">
+						<!-- #ifdef MP-WEIXIN -->
+						<image :src="avatarUrl" mode=""></image>
+						<!-- #endif -->
+						<!-- #ifdef H5 -->
+						<image :src="faceUrl" mode=""></image>
+						<!-- #endif -->
+					</view>
+				</view>
+				<view class="btns">
+					<!-- <view class="btnResult" v-if="isTaking" @click="takePhoto"
+              >拍照</view
+            > -->
+					<view v-if="isTaking" class="takePhoto_btn">
+						<view style="width: 100rpx; height: 2rpx"></view>
+						<view class="">
+							<button style="float: left;" :type="status === 3 ? 'primary' : 'primary'" class="pos"
+								@click="luzhi" :disabled="status === 2">{{
+            status === 1 ? "开始录制3秒" : status === 2 ? "录制中" : "提交"
+          }}</button>
+							<button @click="again" type="primary" style="float: left;
+    margin-left: 20px;" v-if="status === 3">重录</button>
+							<!-- <view class="btnResult" @click="luzhi()">重拍</view> -->
+							<!-- <view class="square"></view> -->
+						</view>
+						<view class="rights" @click="takePhTips()">
+							<text>抽查提示</text>
+							<u-icon name="arrow-right" color="#FFFFFF" size="30"></u-icon>
+						</view>
+					</view>
+					<view class="btnResult" v-if="!isTaking" @click="reTake">重拍</view>
+					<view class="btnResult" v-if="!isTaking" @click="submit">确认</view>
+				</view>
+			</view>
+		</u-popup>
+		<!-- 播放前拍照end -->
+		<u-popup v-model="showSet" :mask-close-able="false" mode="center" border-radius="24">
+			<view style="
+          align-items: center;
+          padding: 0 40rpx;
+          display: flex;
+          flex-direction: column;
+          justify-content: center;
+        ">
+				<view style="
+            font-weight: bold;
+            color: #333333;
+            font-size: 30rpx;
+            margin-top: 30rpx;
+          ">温馨提示</view>
+				<view style="
+            width: 457rpx;
+            color: #666666;
+            font-size: 30rpx;
+            margin-top: 30rpx;
+          ">学习过程中需要拍照验证学员身份, 拍照功能需要使用您的相机。
+					是否授权使用?</view>
+				<view style="margin: 40rpx 0">
+					<button open-type="openSetting" @bindopensetting="openSetting" class="btnSet">
+						去授权
+					</button>
+				</view>
+			</view>
+		</u-popup>
+		<!-- 拍照提示 -->
+		<u-popup v-model="popupPhotoShow" mode="bottom" border-radius="30" :mask-close-able='false'>
+			<view class="popup_box">
+				<view class="head">
+					<image src="/static/learn/photo_head.png" class="photo_head"></image>
+				</view>
+				<view class="warn">温馨提示</view>
+				<view class="contents">
+					<view class="words">1、本次为抽查检测,需要录制3秒的视频。</view>
+					<view class="words">2、请保证摄像头正对自己,避免头像偏左或者偏右。</view>
+					<view class="words">3、请保证拍照环境光线充足(照片太暗或曝光会降低验证通过率)。</view>
+					<view class="words">4、请保证整个头像在人脸识别区域内,脸部无遮挡装饰物(佩戴眼镜会降低通过率)。</view>
+					<view class="words">5、如果下面视频中出现黑屏,摄像头可能被其他进程占用,请关闭其他调用摄像头的程序,重新刷新当前页面重新拍照识别。</view>
+				</view>
+				<view class="take_photo" @click="openCamera">
+					去录像
+				</view>
+			</view>
+		</u-popup>
+	</view>
+</template>
+
+<script>
+	import myCompressImage from "@/common/compressPhoto.js";
+	import PopupPhoto from "./index.vue";
+	export default {
+		name: "SaasMiniprogramCamera",
+		inject: ["paramsFn"],
+		props: {
+			visible: {
+				type: Boolean,
+				default: false,
+			},
+		},
+		data() {
+			return {
+				isShow: false,
+				isTaking: true,
+				avatarUrl: "",
+				isCameraAuth: false,
+				showSet: false,
+				popupPhotoShow: false,
+				status: 1, //1未录制 2录制中 3录制完成
+				takeVideoModal: false,
+				mediaRecorder: null,
+				videoblob: null,
+				url: null,
+				faceUrl: null,
+			};
+		},
+		methods: {
+			error(err) {
+				console.log(err)
+			},
+			async submit() {
+				if (this.uploadLock) {
+					return;
+				}
+				this.uploadLock = true;
+				let imgUrl = await this.imageInfos()
+				let compareFaceData = await this.faceRecognition(imgUrl);
+				if (compareFaceData.code === 200) {
+					this.$emit("submitTakeVideo", this.videoblob);
+					this.closeCamera();
+				} else {
+					uni.showToast({
+						title: compareFaceData.msg,
+						icon: "none",
+						duration: 2000,
+					});
+
+					setTimeout(() => {
+						if (!this.isTaking) {
+							this.reTake();
+						}
+					}, 2000);
+				}
+			},
+			async imageInfos() {
+				let resPath = await myCompressImage(this.avatarUrl || this.faceUrl, 50);
+				const waitUpload = await this.$method.uploadFile(resPath, 0);
+				return waitUpload;
+			},
+			closeCamera() {
+				this.isShow = false;
+				this.showSet = false;
+				this.popupPhotoShow = false;
+			},
+
+			openCamera() {
+				console.log("openCamera");
+				this.uploadLock = false;
+				this.popupPhotoShow = false;
+				// 同一个商品只谈一次提示
+				// let popupList = uni.getStorageSync("popupList") || [];
+				// if (!popupList.includes(this.goodsId)) {
+				// 	popupList.push(this.goodsId);
+				// 	uni.setStorageSync("popupList", popupList);
+				// 	this.popupPhotoShow = true;
+				// 	return;
+				// }
+				// #ifdef MP-WEIXIN
+				// 屏幕亮度
+				uni.setKeepScreenOn({
+					keepScreenOn: true,
+				});
+				uni.getSetting({
+					success: (res) => {
+						if (res.authSetting["scope.camera"]) {
+							this.isCameraAuth = true;
+							this.showCamera();
+						} else {
+							wx.authorize({
+								scope: "scope.camera",
+								success: () => {
+									this.isCameraAuth = true;
+									this.showCamera();
+								},
+								fail: () => {
+									this.isCameraAuth = false;
+									this.showSet = true;
+								},
+							});
+						}
+					},
+					fail: (res) => {},
+				});
+				// #endif
+				// #ifdef H5
+				if (
+					(window.navigator.mediaDevices &&
+						window.navigator.mediaDevices.getUserMedia) ||
+					window.navigator.getUserMedia ||
+					window.navigator.webkitGetUserMedia ||
+					window.navigator.mozGetUserMedia
+				) {
+					console.log("getUserMedia----");
+					// 调用用户媒体设备, 访问摄像头
+					this.getUserMedia({
+							video: {
+								width: 400,
+								height: 400,
+								facingMode: "user",
+							},
+						},
+						this.photographSuccess,
+						this.photographError
+					);
+				} else {
+					console.log("1111没有摄像");
+					this.photographError();
+				}
+				// #endif
+			},
+			showCamera() {
+				this.isTaking = true;
+				this.isShow = true;
+			},
+			//确认拍照
+			takePhoto() {
+				// #ifdef MP-WEIXIN
+				const ctx = uni.createCameraContext();
+				ctx.startRecord
+				ctx.takePhoto({
+					quality: "high",
+					success: (res) => {
+						this.avatarUrl = res.tempImagePath;
+						console.log("开始拍照this.avatarUrl:", this.avatarUrl);
+						this.isTaking = false;
+					},
+					fail: (err) => {},
+				});
+				// #endif
+				// #ifdef H5
+				this.luzhi();
+				// const canvas = document.createElement("canvas");
+				// canvas.width = 400;
+				// canvas.height = 400;
+				// const context = canvas.getContext("2d");
+				// const box = document.querySelector(".photo_v");
+				// const video = box.querySelector("video");
+				// context.drawImage(video, 0, 0, 400, 400);
+				// this.faceUrl = canvas.toDataURL("image/png");
+				// this.isTaking = false;
+				// #endif
+			},
+			takePhTips() {
+				this.popupPhotoShow = true;
+				this.isShow = false;
+				this.isTaking = false;
+			},
+			/**
+			 * 人脸匹配
+			 */
+			faceRecognition(url) {
+				return new Promise((resolve) => {
+					// // #ifdef MP-WEIXIN
+					// let fileSystem = uni.getFileSystemManager();
+					// fileSystem.readFile({
+					// 	filePath: `${this.avatarUrl}`,
+					// 	encoding: "base64",
+					// 	position: 0,
+					// 	success: (res) => {
+					// 		let base64 = "data:image/jpg;base64," + res.data;
+					// 		this.CompareFace(base64, resolve);
+					// 	},
+					// 	fail(err) {
+					// 		// this.$u.toast('人脸识别错误!')
+					// 		console.error(err, "err-----人脸识别错误");
+					// 	},
+					// });
+					// // #endif
+					// // #ifdef H5
+					// this.CompareFace(this.faceUrl, resolve);
+					// // #endif
+					this.CompareFace(url, resolve);
+				});
+			},
+			CompareFace(url, resolve) {
+				let timer = setTimeout(() => {
+					uni.showToast({
+						icon: "none",
+						title: "录像超时,请重新录制视频",
+						duration: 2000,
+						success: () => {
+							setTimeout(() => {
+								uni.navigateBack();
+							}, 1000);
+						},
+					});
+				}, 10 * 1000);
+
+				this.$api
+					.faceCertificationCompareFace({
+						urlA: url,
+						// imageA: url,
+						orderGoodsId: this.params.orderGoodsId,
+						gradeId: this.params.gradeId,
+					})
+					.then((res) => {
+						clearTimeout(timer);
+						console.log(res, "人脸识别成功res");
+						resolve(res.data);
+					})
+					.catch((err) => {
+						clearTimeout(timer);
+						// 当前网络延迟,
+						console.log("人脸识别错误:", err);
+						uni.showModal({
+							content: "当前网络延迟",
+							showCancel: false,
+							success: (resultst) => {
+								if (resultst.confirm) {
+									uni.navigateBack();
+								}
+							},
+						});
+					});
+			},
+			photographSuccess(stream) {
+				console.log("有摄像头---", stream);
+				this.isCameraAuth = true;
+				this.showCamera();
+				this.$nextTick(() => {
+					const box = document.querySelector(".photo_v");
+					const video = box.querySelector("video");
+					video.srcObject = stream;
+					this.mediaRecorder = new MediaRecorder(stream);
+					video.play();
+				});
+			},
+			photographError(err) {
+				console.log("没有摄像头:", err);
+				uni.showModal({
+					title: "提示",
+					content: "课程学习需要开启摄像头进行拍照,经检测您的设备无摄像头可使用,请检测环境是否支持。",
+
+					cancelText: "取消",
+					confirmText: "确定",
+					showCancel: false,
+					success: (res) => {
+						if (res.confirm) {
+							uni.navigateBack();
+						} else if (res.cancel) {}
+					},
+				});
+			},
+			getUserMedia(constraints, success, error) {
+				console.log("getUserMedia===", constraints);
+				if (window.navigator.mediaDevices.getUserMedia) {
+					// 最新的标准API
+					window.navigator.mediaDevices
+						.getUserMedia(constraints)
+						.then(success)
+						.catch(error);
+				} else if (window.navigator.webkitGetUserMedia) {
+					// webkit核心浏览器
+					window.navigator.webkitGetUserMedia(constraints, success, error);
+				} else if (window.navigator.mozGetUserMedia) {
+					// firfox浏览器
+					window.navigator.mozGetUserMedia(constraints, success, error);
+				} else if (window.navigator.getUserMedia) {
+					// 旧版API
+					window.navigator.getUserMedia(constraints, success, error);
+				}
+			},
+			again() {
+				this.url = null;
+				this.status = 1;
+			},
+			luzhi() {
+				if (this.status === 3) {
+					//完成提交
+					this.submit();
+					return;
+				}
+				this.onCatchPhoto();
+				this.mediaRecorder.start();
+				this.status = 2;
+				setTimeout(() => {
+					this.stop();
+					this.status = 3;
+				}, 3500);
+			},
+			//拍照
+			onCatchPhoto() {
+				const canvas = document.createElement("canvas");
+				canvas.width = 400;
+				canvas.height = 400;
+				const context = canvas.getContext("2d");
+				const box = document.querySelector(".photo_v");
+				const video = box.querySelector("video");
+				context.drawImage(video, 0, 0, 400, 400);
+				this.faceUrl = canvas.toDataURL("image/png");
+				// console.log(this.faceUrl,'faceUrl')
+			},
+			stop() {
+				this.mediaRecorder.stop();
+				this.mediaRecorder.ondataavailable = (event) => {
+					//this.$message.success("录制完成");
+					// console.log(event.data, 'data')
+					// 尝试转换为mp4类型
+					const blob = event.data.slice(0, event.data.size, "video/mp4");
+					this.url = URL.createObjectURL(blob);
+					this.videoblob = blob;
+					console.log(event.data, 'url')
+					// const file = new window.File([blob], "videoss.mp4", {
+					//     type: 'video/mp4',
+					// });
+					// console.log(file, 'file')
+				};
+			},
+		},
+		computed: {
+			params() {
+				return this.paramsFn();
+			},
+			goodsId() {
+				return this.params.goodsId;
+			},
+		},
+		components: {
+			PopupPhoto,
+		},
+		watch: {
+			visible(val) {
+				if (val) {
+					this.takePhTips()//this.openCamera();
+				} else {
+					this.closeCamera();
+				}
+			},
+		},
+	};
+</script>
+
+<style lang="scss" scoped>
+	.btnSet {
+		width: 440rpx;
+		height: 80rpx;
+		background: #007aff;
+		border-radius: 40rpx;
+		color: #ffffff;
+		font-size: 28rpx;
+		line-height: 80rpx;
+	}
+
+	.photoBox {
+		width: 100%;
+
+		.photoTop {
+			width: 100%;
+			height: 74rpx;
+			border-radius: 20px 20px 0px 0px;
+			background-color: #ffffff;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			padding: 0rpx 38rpx;
+
+			.centersq {
+				color: #333;
+				font-size: 30rpx;
+				font-weight: 500;
+			}
+		}
+
+		.photoCenter {
+			width: 750rpx;
+			height: 75vh;
+			position: relative;
+
+			.center_camera {
+				width: 100%;
+				height: 75vh;
+				position: fixed;
+				background-color: rgba(0, 0, 0, .8);
+
+				.head_take {
+					width: 100%;
+					height: 75vh;
+					display: flex;
+					flex-direction: column;
+				}
+
+				.headTake_up {
+					width: 100%;
+					height: 100rpx;
+				}
+
+				.headTake_minddle {
+					display: flex;
+
+					.min_img {
+						width: 500rpx;
+						height: 550rpx;
+					}
+
+					.min_left,
+					.min_right {
+						flex: 1;
+						height: 550rpx;
+					}
+				}
+
+				.headTake_down {
+					width: 100%;
+					flex: 1;
+				}
+
+				.color {
+					background-color: #333;
+					opacity: 0.5;
+				}
+
+				.photo_v {
+					display: block;
+					margin: 0 auto;
+					width: 400px;
+					height: 400px;
+				}
+
+				.photo_v2 {
+					display: block;
+					margin: 0 auto;
+					width: 400px;
+					height: 400px;
+				}
+
+				.mask {
+					width: 500rpx;
+					height: 550rpx;
+					position: absolute;
+					top: 100rpx;
+					left: 0;
+					right: 0;
+					bottom: 0;
+					margin: 0 auto;
+					box-shadow: 0 0 0 2000px rgba(0, 0, 0, 0.4);
+				}
+			}
+
+			.custom {
+				width: 750rpx;
+				height: 75vh;
+				position: absolute;
+				z-index: 1000;
+				top: 0;
+				left: 0;
+				background-color: rgba(0, 0, 0, .8);
+
+				image {
+					display: block;
+					margin: 0 auto;
+					width: 400px;
+					height: 400px;
+				}
+			}
+		}
+
+		.btns {
+			display: flex;
+
+			.takePhoto_btn {
+				width: 100%;
+				display: flex;
+				align-items: center;
+				justify-content: space-between;
+				background: #a9a7a9;
+				padding: 40rpx 26rpx;
+
+				.middle_btn {
+					width: 120rpx;
+					height: 120rpx;
+					border-radius: 40rpx;
+					border: 4rpx solid #ffffff;
+					display: flex;
+					align-items: center;
+					justify-content: center;
+				}
+
+				.square {
+					width: 96rpx;
+					height: 96rpx;
+					background: #ffffff;
+					border-radius: 28rpx;
+				}
+
+				.rights {
+					font-size: 32rpx;
+					font-weight: 500;
+					color: #ffffff;
+				}
+			}
+
+			.btnResult {
+				height: 100rpx;
+				flex: 1;
+				background-color: #07c160;
+				text-align: center;
+				line-height: 100rpx;
+				color: #fff;
+				font-size: 32rpx;
+				font-weight: bold;
+			}
+		}
+	}
+
+	.popup_box {
+		width: 100%;
+		height: 1100rpx;
+		display: flex;
+		align-items: center;
+		flex-direction: column;
+		padding: 0rpx 40rpx;
+
+		.photo_head {
+			width: 240rpx;
+			height: 240rpx;
+			margin: 80rpx 0rpx 48rpx;
+		}
+
+		.warn {
+			width: 100%;
+			font-size: 36rpx;
+			font-weight: bold;
+			color: #222222;
+			margin-bottom: 40rpx;
+		}
+
+		.words {
+			font-size: 28rpx;
+			color: #666666;
+			line-height: 33rpx;
+			margin-bottom: 24rpx;
+		}
+
+		.take_photo {
+			width: 412rpx;
+			height: 84rpx;
+			line-height: 84rpx;
+			text-align: center;
+			background: #01C65A;
+			border-radius: 16rpx;
+			font-size: 36rpx;
+			font-weight: 500;
+			color: #FFFFFF;
+			margin-top: 100rpx;
+		}
+	}
+</style>

+ 11 - 0
pages.json

@@ -86,6 +86,17 @@
 						}
 					}
 				},
+				{
+					"path": "wd/pwd",
+					"style": {
+						"navigationBarTitleText": "修改密码",
+						"navigationStyle": "custom", // 隐藏系统导航栏
+						"app-plus": {
+							"titleNView": false, //禁用原生导航栏
+							"bounce": "none"
+						}
+					}
+				},
 				{
 					"path": "wd/menu", //没有用到
 					"style": {

+ 4 - 3
pages/learn/index.vue

@@ -328,7 +328,7 @@
                   item.classEndTime < sysTime &&
                   (item.periodStatus == 0 || item.periodStatus == -1)
                 ">
-								<span v-if="item.studyCount > 0">温馨提示:班级已过期,如需重新学习,请点击右侧“选班重学”按钮。</span>
+								<span v-if="item.studyCount > 0&&userInfo.studentRestudy!=1">温馨提示:班级已过期,如需重新学习,请点击右侧“选班重学”按钮。</span>
 								<span v-else>温馨提示:班级已过期,您的重学次数已用完,如有疑问请联系{{
                     eduPhone
                   }}</span>
@@ -338,7 +338,8 @@
 							</div>
 							<!-- 关于二建继教通过提示 -->
 							<div v-if="item.periodStatus === 1 && isTwoEducation(item)">
-								温馨提示:您的学时{{ $method.timestampToTime(item.periodTime) }}机构已审核通过,
+								温馨提示:您的学时<!-- {{ $method.timestampToTime(item.periodTime) }} -->
+								机构已通过初审,
 								需等待信息中心约15个工作日复审通过后即可获得继续教育学时,届时请前往信息中心官网查看学时及申请证书延期。
 								<span style="color: #2f9aff; cursor: pointer;"
 									@click="goPage('http://gdzczx.gdcic.net/', 2)"> 复制官网链接 </span>
@@ -370,7 +371,7 @@
                   item.classEndTime &&
                   item.classEndTime < sysTime &&
                   (item.periodStatus == 0 || item.periodStatus == -1) &&
-                  item.userStudyCount > 0
+                  item.userStudyCount > 0 && userInfo.studentRestudy!=1
                 ">
 								<view class="exam_word ones" @click.stop="selectClass(item, index)">
 									选班重学

+ 9 - 0
pages/wd/index.vue

@@ -80,6 +80,15 @@
 						<u-icon name="arrow-right" color="#999" size="24"></u-icon>
 					</view>
 				</navigator>
+				<navigator hover-class="none" url="/pages2/wd/pwd" class="menu_box">
+					<view class="box_left">
+						<image src="/static/icon/my_icon9.png" class="my_icon"></image>
+						<view>修改密码</view>
+					</view>
+					<view class="box_right">
+						<u-icon name="arrow-right" color="#999" size="24"></u-icon>
+					</view>
+				</navigator>
 				<navigator hover-class="none" url="/pages2/wd/stuff" class="menu_box">
 					<view class="box_left">
 						<image src="/static/icon/my_icon14.png" class="my_icon"></image>

+ 16 - 4
pages2/class/questionBank.vue

@@ -741,6 +741,7 @@
 				simulateExamId: undefined,
 				isBackVideo: "",
 				isReach: false, //599重拍
+				stream:null,
 			};
 		},
 		watch: {
@@ -1183,7 +1184,7 @@
 					.then((res) => {
 						clearTimeout(timer);
 						console.log(res, "人脸识别成功res");
-						resolve(res.data.data);
+						resolve(res.data);
 					})
 					.catch((err) => {
 						clearTimeout(timer);
@@ -1217,13 +1218,14 @@
 				this.uploadLock = true;
 				const waitYS = await this.imageInfos();
 				let compareFaceData = await this.faceRecognition(waitYS);
-				this.compareFaceData = compareFaceData;
-				if (compareFaceData >= 80) {
+				if (compareFaceData.code === 200) {
+				this.compareFaceData = compareFaceData.data;
 					this.postStudyRecord(); //提交记录
 					this.photoPopup = false;
+					this.stopCamera();
 				} else {
 					uni.showToast({
-						title: "人脸匹配不通过,请重新拍照上传",
+						title: compareFaceData.msg,
 						icon: "none",
 						duration: 2000,
 					});
@@ -1267,6 +1269,7 @@
 							video: {
 								width: 400,
 								height: 300,
+								facingMode: "user",
 							},
 						},
 						this.photographSuccess,
@@ -1305,6 +1308,14 @@
 				this.isTaking = false;
 				// #endif
 			},
+			//释放摄像头
+			stopCamera() {
+				if (this.stream) {
+						    this.stream.getVideoTracks().forEach(track => track.stop());
+							console.log('释放占用摄像头');
+						    this.stream = null;
+						  }
+			},
 			/**
 			 * 是否有上传图片
 			 */
@@ -2532,6 +2543,7 @@
 					console.log("video:", video);
 					video.srcObject = stream;
 					video.play();
+					this.stream=stream;
 				});
 			},
 			photographError(err) {

+ 1 - 1
pages2/invoice/index.vue

@@ -92,7 +92,7 @@
 						<u-form-item label="选择订单" label-width="150" required prop="orderGoodsIds"
 							right-icon="arrow-right" ref="orderGoodsIds">
 							<view class="form-item" @click="selectOrderModal = true">
-								<u-input placeholder="请点击选择订单" disabled @click="selectOrderModal = true" />
+								<u-input placeholder="请点击选择订单" style="pointer-events: none;" readonly @click="selectOrderModal = true" />
 							</view>
 						</u-form-item>
 						<view>

+ 1 - 0
pages2/order/index.vue

@@ -60,6 +60,7 @@
                         item.orderStatus === 3) &&
                       (items.goodsType == '1' ||
                         items.goodsType == '2' ||
+                        items.goodsType == '3' ||
                         items.goodsType == '6') &&
                       items.goodsPrice > 0
                     " class="btn2" @click.stop="handelRefund(item.orderSn, items)">申请退款</view>

+ 71 - 2
pages2/register/forget.vue

@@ -30,7 +30,7 @@
               placeholder-style="color:#999999"
               placeholder="验证码"
             />
-            <u-button slot="right" size="mini" @click="getCode">{{
+            <u-button slot="right" size="mini" @click="getCodepre">{{
               codeTips
             }}</u-button>
           </u-form-item>
@@ -67,6 +67,19 @@
       ref="uCode"
       @change="codeChange"
     ></u-verification-code>
+	<u-popup v-model="codeModal" :mask-close-able="false" closeable mode="center" width="80%" border-radius="24">
+		<view class="rf-popup-main">
+			<view class="title">获取手机验证码</view>
+			<u-form >
+				<u-form-item prop="imageCode">
+							<u-input v-model="imageCode" type="number" placeholder-style="color:#999999"
+								placeholder="图形验证码" />
+							 <image slot="right" style="width: 212rpx;height: 80rpx;margin-bottom: 40rpx;"  :src="codeUrl" @click="getCodepre"></image>
+						 </u-form-item>
+			</u-form>
+			<u-button type="primary" style="border-radius: 60rpx;" @click="getCode">获取手机验证码</u-button>
+		</view>
+	</u-popup>
   </view>
 </template>
 
@@ -75,6 +88,10 @@ export default {
   data() {
     return {
       code: "",
+	  codeModal: false,
+	  imageCode:"",
+	  imageUuid:"",
+	  codeUrl:"",
       form: {
         code: "",
         tel: "",
@@ -195,15 +212,42 @@ export default {
     codeChange(text) {
       this.codeTips = text;
     },
+	//获取图形验证码
+	getCodepre(){
+		this.codeModal=true;
+		this.$api.captchaImage({}).then(
+			(res) => {
+				if (res.data.code == 200) {
+					this.codeUrl = "data:image/gif;base64," + res.data.data.img;
+					this.imageUuid= res.data.data.uuid;
+				} else {
+					this.$u.toast(res.data.msg);
+				}
+			},
+			(err) => {
+				console.log(err);
+			}
+		);
+	},
     // 获取验证码
     getCode() {
       let that = this;
+	  if(!this.imageCode)
+	  {
+	  	that.$u.toast("请输入图形验证码");
+	  	return;
+	  }
       if (that.$refs.uCode.canGetCode) {
         if (that.$refs.tel.validateState == "success") {
-          let datas = { tel: this.form.tel };
+          let datas = { 
+			  tel: this.form.tel ,
+		      imageCode:this.imageCode,
+			  imageUuid:this.imageUuid,
+			  };
           that.$api.forgetSms(datas).then(
             (res) => {
               if (res.data.code == 200) {
+				  	this.codeModal=false;
                 that.$u.toast("验证码已发送");
                 // 通知验证码组件内部开始倒计时
                 that.$refs.uCode.start();
@@ -329,4 +373,29 @@ export default {
   text-align: center;
   margin-top: 10rpx;
 }
+.rf-popup-main {
+		text-align: center;
+		padding: 40rpx;
+	
+		.title {
+			font-size: 40rpx;
+			font-weight: 600;
+		}
+	
+		.tip {
+			margin: 30rpx 0 40rpx;
+			font-size: 32rpx;
+		}
+	
+		.u-input {
+			border-radius: 20rpx;
+			background: #eee;
+			padding-left: 20rpx !important;
+			margin-bottom: 40rpx;
+		}
+	
+		.u-button {
+			border-radius: 60rpx !important;
+		}
+	}
 </style>

+ 70 - 2
pages2/register/register.vue

@@ -11,7 +11,7 @@
 					<u-form-item prop="code">
 						<u-input v-model="form.code" type="number" placeholder-style="color:#999999"
 							placeholder="验证码" />
-						<u-button slot="right" size="mini" @click="getCode">{{
+						<u-button slot="right" size="mini" @click="getCodepre">{{
               codeTips
             }}</u-button>
 					</u-form-item>
@@ -422,6 +422,20 @@
 				</view>
 			</view>
 		</u-popup>
+		<u-popup v-model="codeModal" :mask-close-able="false" closeable mode="center" width="80%" border-radius="24">
+			<view class="rf-popup-main">
+				<view class="title">获取手机验证码</view>
+				<u-form >
+					<u-form-item prop="imageCode">
+								<u-input v-model="imageCode" type="number" placeholder-style="color:#999999"
+									placeholder="图形验证码" />
+							 <image slot="right" style="width: 212rpx;height: 80rpx;margin-bottom: 40rpx;"  :src="codeUrl" @click="getCodepre"></image>
+							 </u-form-item>
+				</u-form>
+				<u-button type="primary" style="border-radius: 60rpx;" @click="getCode">获取手机验证码</u-button>
+			</view>
+		</u-popup>
+		
 	</view>
 </template>
 
@@ -430,6 +444,10 @@
 		data() {
 			return {
 				agreementModal: false,
+				codeModal: false,
+				imageCode:"",
+				imageUuid:"",
+				codeUrl:"",
 				isAgree: false,
 				form: {
 					code: "",
@@ -637,17 +655,42 @@
 			codeChange(text) {
 				this.codeTips = text;
 			},
+			//获取图形验证码
+			getCodepre(){
+				this.codeModal=true;
+				this.$api.captchaImage({}).then(
+					(res) => {
+						if (res.data.code == 200) {
+							this.codeUrl = "data:image/gif;base64," + res.data.data.img;
+							this.imageUuid= res.data.data.uuid;
+						} else {
+							this.$u.toast(res.data.msg);
+						}
+					},
+					(err) => {
+						console.log(err);
+					}
+				);
+			},
 			// 获取验证码
 			getCode() {
 				let that = this;
+				if(!this.imageCode)
+				{
+					that.$u.toast("请输入图形验证码");
+					return;
+				}
 				if (that.$refs.uCode.canGetCode) {
 					if (that.$refs.tel.validateState == "success") {
 						let datas = {
-							tel: this.form.tel
+							tel: this.form.tel,
+							imageCode:this.imageCode,
+							imageUuid:this.imageUuid
 						};
 						that.$api.registerSms(datas).then(
 							(res) => {
 								if (res.data.code == 200) {
+									this.codeModal=false;
 									that.$u.toast("验证码已发送");
 									// 通知验证码组件内部开始倒计时
 									that.$refs.uCode.start();
@@ -833,4 +876,29 @@
 			}
 		}
 	}
+	.rf-popup-main {
+		text-align: center;
+		padding: 40rpx;
+	
+		.title {
+			font-size: 40rpx;
+			font-weight: 600;
+		}
+	
+		.tip {
+			margin: 30rpx 0 40rpx;
+			font-size: 32rpx;
+		}
+	
+		.u-input {
+			border-radius: 20rpx;
+			background: #eee;
+			padding-left: 20rpx !important;
+			margin-bottom: 40rpx;
+		}
+	
+		.u-button {
+			border-radius: 60rpx !important;
+		}
+	}
 </style>

+ 31 - 0
pages2/verify/input.vue

@@ -150,6 +150,11 @@
                     "></image>
 								</template>
 							</u-upload>
+							<text style="vertical-align: bottom;color: orange;display: block;line-height: 1.1;" >{{
+							                    item.fieldKey == "recent_photos"
+							                      ? "模糊或者大小异常的照片将影响学习,请勿使用身份证代替标准照上传。"
+							                      : "请剪裁至合适大小,并且身份证方向不能倒置。"
+							                  }}</text>
 						</u-form-item>
 						<view :key="index" v-if="
                 item.inputType == 3 &&
@@ -486,6 +491,21 @@
 			!this.userInfo && this.$api.refreshUserInfo();
 			await this.getGoodsDetail();
 			await this.getInfo();
+					// console.log("sda111", this.userInfo);
+					if (this.userInfo.oneInchPhotos&&!this.form.recent_photos) {
+						this.form.recent_photos = this.userInfo.oneInchPhotos;
+						this.recent_photos_old = this.userInfo.oneInchPhotos;
+						this.fileList1=[{url:this.baseUrls+this.userInfo.oneInchPhotos}];
+					}
+					if (this.userInfo.idCardImg1&&!this.form.idcard_face_photo) {
+						this.form.idcard_face_photo = this.userInfo.idCardImg1;
+						this.idcard_face_photo_old = this.userInfo.idCardImg1;
+						this.fileList2=[{url:this.baseUrls+this.userInfo.idCardImg1}];
+					}
+					if (this.userInfo.idCardImg2&&! this.form.idcard_national_photo) {
+						this.form.idcard_national_photo = this.userInfo.idCardImg2;
+						this.fileList3=[{url:this.baseUrls+this.userInfo.idCardImg2}];
+					}
 		},
 		onReady(res) {
 			this.handwriting = new Handwriting({
@@ -505,6 +525,7 @@
 			userInfo(val, oldVal) {
 				//普通的watch监听
 				if (val) {
+					console.log("sda", this.userInfo);
 					this.listData.forEach((item) => {
 						if (item.fieldKey == "idcard") {
 							this.form.idcard = this.userInfo.idCard;
@@ -516,7 +537,17 @@
 						if (item.fieldKey == "name") {
 							this.form.name = this.userInfo.realname;
 						}
+						if (item.fieldKey == "recent_photos") {
+							this.form.recent_photos = this.userInfo.oneInchPhotos;
+						}
+						if (item.fieldKey == "idcard_face_photo") {
+							this.form.idcard_face_photo = this.userInfo.idCardImg1;
+						}
+						if (item.fieldKey == "idcard_national_photo") {
+							this.form.idcard_national_photo = this.userInfo.idCardImg2;
+						}
 					});
+					// console.log("sdasdada", this.form);
 				}
 			},
 		},

+ 14 - 0
pages2/verify/input_tang.vue

@@ -410,6 +410,20 @@
 			!this.userInfo && this.$api.refreshUserInfo();
 			await this.getGoodsDetail();
 			await this.getInfo();
+					if (this.userInfo.oneInchPhotos&&!this.form.recent_photos) {
+						this.form.recent_photos = this.userInfo.oneInchPhotos;
+						this.recent_photos_old = this.userInfo.oneInchPhotos;
+						this.fileList1=[{url:this.baseUrls+this.userInfo.oneInchPhotos}];
+					}
+					if (this.userInfo.idCardImg1&&!this.form.idcard_face_photo) {
+						this.form.idcard_face_photo = this.userInfo.idCardImg1;
+						this.idcard_face_photo_old = this.userInfo.idCardImg1;
+						this.fileList2=[{url:this.baseUrls+this.userInfo.idCardImg1}];
+					}
+					if (this.userInfo.idCardImg2&&! this.form.idcard_national_photo) {
+						this.form.idcard_national_photo = this.userInfo.idCardImg2;
+						this.fileList3=[{url:this.baseUrls+this.userInfo.idCardImg2}];
+					}
 		},
 		onReady(res) {
 			this.handwriting = new Handwriting({

+ 279 - 0
pages2/wd/pwd.vue

@@ -0,0 +1,279 @@
+<template>
+  <view style="height: 100%">
+    <image
+      mode="widthFix"
+      src="/pages2/static/login_bg.jpg"
+      class="full_img"
+    ></image>
+    <u-navbar
+      title="修改密码"
+      :border-bottom="false"
+      background="{ background: '#ffffff',opacity:0.4; }"
+      title-color="#ffffff"
+      back-icon-color="#ffffff"
+    ></u-navbar>
+    <view style="padding: 30rpx">
+      <view class="login_box">
+        <u-form :model="form" ref="uForm">
+         <u-form-item prop="oldpwd"
+           ><u-input
+             class="password"
+             placeholder-style="color:#999999"
+             v-model="form.oldpwd"
+             type="password"
+             placeholder="请输入旧密码"
+         /></u-form-item>
+          <u-form-item prop="pwd"
+            ><u-input
+              class="password"
+              placeholder-style="color:#999999"
+              v-model="form.pwd"
+              type="password"
+              placeholder="请输入新密码"
+          /></u-form-item>
+          <u-form-item prop="pwdAgain"
+            ><u-input
+              class="password"
+              placeholder-style="color:#999999"
+              v-model="form.pwdAgain"
+              type="password"
+              placeholder="再次输入新密码"
+          /></u-form-item>
+        </u-form>
+      </view>
+
+      <button
+        :disabled="isUse"
+        class="loginBtn"
+        :class="{ able: canSubmit() }"
+        @click="submit"
+      >
+        确定
+      </button>
+    </view>
+    <u-verification-code
+      seconds="60"
+      ref="uCode"
+      @change="codeChange"
+    ></u-verification-code>
+	<!-- <u-navbar   title="" :border-bottom="false" background="{ background: '#ffffff',opacity:0.4; }" title-color="#ffffff" back-icon-color="#ffffff">
+		
+	</u-navbar> -->
+  </view>
+</template>
+
+<script>
+	import {mapGetters} from 'vuex';
+export default {
+  data() {
+    return {
+      code: "",
+      form: {
+        code: "",
+        tel: "",
+        pwd: "",
+        pwdAgain: "",
+      },
+      rules: {
+        pwd: [
+          {
+            required: true,
+            message: "请输入密码",
+            // 可以单个或者同时写两个触发验证方式
+            trigger: ["change"],
+          },
+        ],
+        pwdAgain: [
+          {
+            required: true,
+            message: "请输入密码",
+            // 可以单个或者同时写两个触发验证方式
+            trigger: ["change"],
+          },
+        ],
+        oldpwd: [
+          {
+            required: true,
+            message: "请输入旧密码",
+            // 可以单个或者同时写两个触发验证方式
+            trigger: ["change"],
+          },
+        ],
+      },
+      codeTips: "",
+      read: "",
+      isUse: false,
+    };
+  },
+  methods: {
+    canSubmit() {
+      if (
+        this.form.oldpwd &&
+        this.form.pwd &&
+        this.form.pwdAgain
+      ) {
+        return true;
+      }
+      return false;
+    },
+    submit() {
+      let that = this;
+      if (!this.form.oldpwd) {
+        this.$u.toast("请输入旧密码");
+        return;
+      }
+      if (!this.form.pwd) {
+        this.$u.toast("请输入新密码");
+        return;
+      }
+      if (!this.form.pwdAgain) {
+        this.$u.toast("请输入确定新密码");
+        return;
+      }
+      if (this.form.pwd != this.form.pwdAgain) {
+        this.$u.toast("两次密码不一致");
+        return;
+      }
+      that.isUse = true;
+	  console.log(this.userInfo,"sda")
+      let datas = {
+        userId: this.userInfo.userId,
+        oldPwd: this.form.oldpwd,
+        newPwd: this.form.pwd,
+      };
+      that.$api.appuserupdatePwd(datas).then(
+        (res) => {
+          that.isUse = false;
+          if (res.data.code == 200) {
+            uni.showModal({
+              title: "提示",
+              content: "修改成功",
+              showCancel: false,
+              success: function (resst) {
+				  // this.$navTo.togo()
+                uni.reLaunch({
+                	url: "/pages/wd/index",
+                });
+              },
+            });
+          } else {
+            that.$u.toast(res.data.msg);
+          }
+        },
+        (err) => {
+          that.isUse = false;
+          console.log(err);
+        }
+      );
+    },
+  },
+  onLoad(option) {
+    let that = this;
+    // this.from = option.from; // 看页面没有用到
+    uni.login({
+      provider: "weixin",
+      success: function (loginRes) {
+        that.code = loginRes.code;
+      },
+    });
+  },
+  onReady() {
+    this.$refs.uForm.setRules(this.rules);
+  },
+  computed: {...mapGetters(['userInfo'])},
+};
+</script>
+
+<style scoped lang="scss">
+.wxBtn {
+  position: fixed;
+  bottom: 10%;
+  width: 100%;
+  left: 0;
+}
+/deep/ .wxBtn button::after {
+  border: none;
+}
+.loginBtn {
+  width: 526rpx;
+  height: 80rpx;
+  background: linear-gradient(90deg, #015eea, #00c0fa);
+  box-shadow: 0rpx 10rpx 16rpx 4rpx rgba(1, 99, 235, 0.04);
+  opacity: 0.6;
+  border-radius: 40rpx;
+  color: #ffffff;
+  text-align: center;
+  line-height: 80rpx;
+  margin: 40rpx auto;
+
+  &.able {
+    opacity: 1;
+  }
+}
+
+.wxloginBtn {
+  background: url("/static/loginBtn.png") no-repeat;
+  background-size: 100% 100%;
+  border: none;
+  width: 100rpx;
+  height: 100rpx;
+}
+
+/deep/page {
+  background-color: #ffffff;
+  height: 100%;
+  width: 100%;
+}
+.login_box {
+  width: 100%;
+  height: 566rpx;
+  background: #ffffff;
+  box-shadow: 0rpx 0rpx 16rpx 4rpx rgba(1, 99, 235, 0.1);
+  border-radius: 24rpx;
+  margin-top: 30rpx;
+  padding: 40rpx 35rpx;
+
+  .password {
+    /deep/.uicon-eye-fill {
+      &::before {
+        color: #007aff;
+        content: "\e613";
+      }
+    }
+  }
+}
+/deep/ .u-item-bg {
+  border-radius: 32px !important;
+}
+/deep/ .u-subsection {
+  border-radius: 32px !important;
+}
+.full_img {
+  position: absolute;
+  left: 0;
+  display: block;
+  width: 100%;
+  z-index: -999;
+  top: 0;
+}
+
+.head {
+  height: 96rpx;
+  width: 100%;
+  line-height: 96rpx;
+  margin-top: 40rpx;
+  text-align: center;
+  display: flex;
+  position: relative;
+  justify-content: center;
+}
+.icon {
+  position: absolute;
+  left: 30rpx;
+}
+.aa {
+  padding: 10rpx;
+  text-align: center;
+  margin-top: 10rpx;
+}
+</style>

+ 4 - 4
pages3/live/detail.vue

@@ -2193,7 +2193,7 @@ export default {
         .then((res) => {
           clearTimeout(timer);
           console.log(res, "人脸识别成功res");
-          resolve(res.data.data);
+          resolve(res.data);
         })
         .catch((err) => {
           clearTimeout(timer);
@@ -2218,8 +2218,8 @@ export default {
       this.uploadLock = true;
         const waitYS = await this.imageInfos();
       let compareFaceData = await this.faceRecognition(waitYS);
-      this.compareFaceData = compareFaceData;
-      if (compareFaceData >= 80) {
+      if (compareFaceData.code === 200) {
+      this.compareFaceData = compareFaceData.data;
         this.postCoursePhotoRecord()
           .then((res) => {
             this.photoHistoryList.push(this.photoIndex);
@@ -2247,7 +2247,7 @@ export default {
           });
       } else {
         uni.showToast({
-          title: "人脸匹配不通过,请重新拍照上传",
+          title: compareFaceData.msg,
           icon: "none",
           duration: 2000,
         });

+ 273 - 2
pages3/polyv/detail.vue

@@ -3,6 +3,13 @@
 		<uni-nav-bar v-if="isShowBar" left-icon="back" :statusBar="true" fixed="true"
 			:title="detail.courseName || '课程详情'" @clickLeft="clickLeft"></uni-nav-bar>
 		<view id="top">
+			<uni-popup ref="popup" :mask-click="false" v-if="goodsData.reminderSign===1">
+				<view style="background: #d6acac;
+    color: #ff3535;
+    padding: 10px;"><text>禁止倍速或拖拽观看,否则学习无效</text>
+					<icon type="cancel" style="float: right;color:#ff3535;" @click="closepopup" size="26" />
+				</view>
+			</uni-popup>
 			<view class="video_box" v-if="!playVid">
 				<image :src="$method.splitImgHost(goodsData.coverUrl)" mode="widthFix"
 					style="width: 100%; height: 421rpx">
@@ -102,6 +109,14 @@
 				</view>
 			</view>
 		</u-popup>
+		<u-modal v-model="noticeShow2" title="提示" @confirm="resetSection" confirm-text="返回重学"
+			:show-cancel-button="false">
+			<view class="slot-content">
+				<text> 系统检测您在学习过程中有拖拽或快进行为,请重新学习!倒计时</text>
+				<text v-if="CountTo2 >= 0" style="color: orange;">{{ " " + CountTo2 + "s " }} </text> 
+				<text> 秒后自动返回重学</text>
+			</view>
+		</u-modal>
 		<u-modal v-model="showMark" title="提示" @confirm="markConfirm" @cancel="toBack" confirm-text="复制学习网址"
 			:show-cancel-button="true" cancel-text="关闭">
 			<view class="slot-content">
@@ -175,6 +190,7 @@
 		</u-popup>
 		<!-- 摄像头 -->
 		<Popup-camera @submitPhoto="submitPhoto" :visible.sync="showCamera" ref="camera" />
+		<Popup-media @submitTakeVideo="submitTakeVideo" :visible.sync="showMedia" ref="media" />
 	</view>
 </template>
 
@@ -182,6 +198,7 @@
 	import handoutsBox from "@/components/course/handoutsBox.vue";
 	import courseTree from "@/components/course/courseTree.vue";
 	import PopupCamera from "../../components/popup/camera.vue";
+	import PopupMedia from "../../components/popup/media.vue";
 	import myPlayer from "@/components/myPlayer/polyvPlayer.vue";
 	import myPlayer2 from "@/components/myPlayer2/tcPlayer.vue";
 	import noteBox from "@/components/course/noteBox.vue";
@@ -207,6 +224,7 @@
 			answerBox,
 			courseTree,
 			PopupCamera,
+			PopupMedia,
 		},
 		data() {
 			return {
@@ -223,6 +241,7 @@
 				goodsId: 0,
 				goodsData: {},
 				showCamera: false,
+				showMedia: false,
 				goodsPlayConfig: null,
 				autoplay: false,
 				isAllowSeek: "no",
@@ -274,7 +293,15 @@
 				beforeHideIsPlaying: false,
 				isLeave: false,
 				text: "",
-				throttleFn: throttle(this.postStudyRecord, 15000)
+				isShowpopuptips: true,
+				throttleFn: throttle(this.postStudyRecord, 15000),
+				needtoTakeVideo: false, //是否需要随机录制2秒视频
+				timeNeedtoTakeVideo: null, //需要随机录制2秒视频定时器
+				curPlayOver: false, //当前视频已播放完毕
+				noticeShow2: false,
+				CountTo2: 0,
+				CountTo2Times: null,
+				reerrorcode:0,
 			};
 		},
 		computed: {
@@ -402,8 +429,41 @@
 			if (!this.userInfo) {
 				await this.$store.dispatch('getUserInfo')
 			}
+			// #ifdef H5
+			if (this.userInfo.slabSign == 1) {
+				if (this.$method.isIPad()) {
+					uni.showModal({
+						title: "提示",
+						content: "暂不支持使用iPad学习,请使用普通手机打开",
+						showCancel: false,
+						complete: () => {
+							uni.switchTab({
+								url: "/pages/learn/index",
+							});
+						}
+					})
+					return
+				}
+				if (this.$method.isTablet()) {
+					uni.showModal({
+						title: "提示",
+						content: "当前页面暂不支持使用平板学习",
+						showCancel: false,
+						complete: () => {
+							uni.switchTab({
+								url: "/pages/learn/index",
+							});
+						}
+					})
+					return
+				}
+			}
+			// #endif
 			this.saveLoaclCheckClass(Number(option.orderGoodsId))
 			this.init();
+			// this.openMedia();
+			// this.showCamera=true;
+
 		},
 		async onShow() {
 			if (!this.$method.isLogin()) {
@@ -521,6 +581,9 @@
 				await this.isCanLearn();
 				this.courseCourseList();
 			},
+			closepopup() {
+				this.goodsData.reminderSign = 0;
+			},
 			// 七大员是否能进入学习
 			async qCheckIsCanLearn() {
 				let res = await this.$api.qCheckIsCanLearn(this.orderGoodsId);
@@ -1172,7 +1235,6 @@
 					data
 				} = await this.$api.goodsDetail(this.goodsId);
 				this.goodsData = data.data;
-
 				if (data.data.firstChoiceStatus) {
 					uni.redirectTo({
 						url: `/pages3/polyv/preference?courseId=${this.courseId}&goodsId=${data.data.goodsId}&orderGoodsId=${this.orderGoodsId}&gradeId=${data.data.gradeId}&minClassHour=${data.data.minClassHour || 0}`,
@@ -1274,6 +1336,10 @@
 				if ((this.photoConfig && this.photoList.length) || !this.isPlaying) {
 					return;
 				}
+				//计算录视频逻辑
+				if (this.needtoTakeVideo) {
+					this.takeVideoLogic();
+				}
 				let totalVideoTime = this.refPlv.getDuration();
 				this.photoConfig = true;
 				if (this.erJianErZao) {
@@ -1374,6 +1440,10 @@
 				// 查找拍照历史
 				if ((this.photoNum > 0 || this.jjShiGongYuan || this.erJianErZao) && learning != 1) {
 					await this.getPhotoLastRecord();
+					// #ifdef H5
+					this.curPlayOver = false;
+					await this.getCheckTakeVideo(); //获取是否需要随机录制3秒视频
+					// #endif
 				}
 				if (this.refPlv) {
 					if (this.playSource == 2) {
@@ -1512,6 +1582,25 @@
 								});
 								this.closeCamera();
 								return
+							} else if (code == 557 || code == 5581 || code == 5591) {
+								this.refPlv.playPause();
+								this.refPlv.exitFullScreen();
+								this.CountTo2 = 180;
+								this.noticeShow2 = true;
+								this.reerrorcode=code;
+								if (this.CountTo2Times) {
+									clearInterval(this.CountTo2Times);
+								}
+								this.CountTo2Times = setInterval(() => {
+									if (this.CountTo2 <= 0) {
+										clearInterval(this.CountTo2Times);
+										this.noticeShow2 = false;
+										this.resetSection(); //重置
+									} else {
+										this.CountTo2--;
+									}
+								}, 1000);
+								return
 							} else if (code == 558) {
 								this.CountTo1 = msg.split(",")[1];
 								this.noticeShow1 = true;
@@ -1544,6 +1633,41 @@
 						});
 				});
 			},
+			resetSection() {
+				if (this.CountTo2Times) {
+					clearInterval(this.CountTo2Times);
+				}
+				if(this.reerrorcode==557)
+				{
+					this.reerrorcode=0;
+					uni.navigateBack();
+					return 
+				}
+				else if(this.reerrorcode==5581||this.reerrorcode==5591){
+				let data = {
+					...this.params([
+						"orderGoodsId",
+						"courseId",
+					]),
+					sectionId: this.sectionId || 0,
+					 errorCode:this.reerrorcode,
+				};
+				this.reerrorcode=0;
+				this.$api
+					.resetSection(data)
+					.then((res) => {
+						console.log(res, "记录返回");
+						let {
+							code,
+							msg
+						} = res.data;
+						uni.navigateBack();
+					})
+					.catch((err) => {
+						uni.navigateBack();
+					});
+					}
+			},
 			timeEvent(time) {
 				console.log(this.refPlv.getDuration(), 'getDurationgetDuration')
 				this.clearPauseTimer();
@@ -1595,6 +1719,13 @@
 			},
 			openCamera() {
 				if (this.showCamera) return;
+				if (this.showMedia) //如果正在录制视频,则5秒后再弹出
+				{
+					setTimeout(() => {
+						this.openCamera();
+					}, 5000);
+					return;
+				}
 				this.showCamera = true;
 				this.refPlv.playPause();
 				this.refPlv.exitFullScreen();
@@ -1615,9 +1746,15 @@
 					icon: "none",
 					title: "播放完毕",
 				});
+				this.curPlayOver = true; //当前视频已播放完毕
+				if (this.needtoTakeVideo) {
+					this.openTakeVideo();
+					return;
+				}
 				this.clearPauseTimer();
 				await this.postStudyRecord(1);
 				this.nextSection();
+				this.curPlayOver = false;
 			},
 			playerError() {
 				console.log("播放错误");
@@ -1800,6 +1937,140 @@
 			) {
 				return this.params(keys);
 			},
+			//计算录视频逻辑
+			takeVideoLogic() {
+				if (!this.needtoTakeVideo) return;
+				if (!this.erJianErZao) return;
+				let totalVideoTime = this.refPlv.getDuration();
+				var duration = this.playTime;
+				var durtime = totalVideoTime - duration;
+				var takevideosec = this.randomNum(
+					durtime > 10 ? 10 : 1,
+					durtime > 310 ? durtime - 300 : durtime - 1
+				); //多少秒后执行
+				clearTimeout(this.timeNeedtoTakeVideo);
+				this.timeNeedtoTakeVideo = setTimeout(() => {
+					this.openTakeVideo();
+				}, takevideosec * 1000);
+				console.log("多少秒后录制", takevideosec * 1000);
+			},
+			//启动录制视频
+			openTakeVideo() {
+				//console.log("showMedia",this.showMedia,this.showCamera)
+				if (!this.needtoTakeVideo) return;
+				if (this.showMedia) return;
+				if (this.showCamera) {
+					this.timeNeedtoTakeVideo = setTimeout(() => {
+						this.openTakeVideo();
+					}, 3000);
+					return;
+				}
+				this.showMedia = true;
+				console.log("showMedia2", this.showMedia, this.showCamera, "弹出录像")
+				this.refPlv.playPause();
+				this.refPlv.exitFullScreen();
+			},
+			//提交录制视频结果
+			postCourseVideoRecord(videoUrl) {
+				return new Promise((resolve, reject) => {
+					var currentTime = this.playTime;
+					let data = {
+						goodsId: this.goodsId,
+						gradeId: this.gradeId,
+						orderGoodsId: this.orderGoodsId,
+						courseId: this.courseId,
+						moduleId: this.moduleId || 0,
+						chapterId: this.chapterId || 0,
+						sectionId: this.sectionId,
+						videoUrl: videoUrl,
+						videoCurrentTime: parseInt(currentTime > 0 ? currentTime : 0),
+						fromPlat: 2, //	来源平台 1小程序 2PC网站 3h5
+					};
+					this.$api
+						.courseTakeVideoRecord(data)
+						.then((res) => {
+							resolve(res);
+						})
+						.catch((err) => {
+							reject();
+						});
+				});
+			},
+			//获取是否需要随机录制2秒视频
+			async getCheckTakeVideo() {
+				return new Promise((resolve) => {
+					var data = {
+						sectionId: this.sectionId,
+						goodsId: this.goodsId,
+						courseId: this.courseId,
+						gradeId: this.gradeId,
+						orderGoodsId: this.orderGoodsId,
+						chapterId: this.chapterId || 0,
+						moduleId: this.moduleId || 0,
+					};
+					this.$api.getCheckTakeVideo(data).then((res) => {
+						this.needtoTakeVideo = res.data.data > 0;
+						resolve();
+					});
+				});
+			},
+			async submitTakeVideo(url) {
+				//上传视频
+				//let file = this.$tools.convertBase64UrlToBlob(url);
+				try {
+					const file = new window.File([url], "video" + this.orderGoodsId.toString() + this.sectionId
+						.toString() + ".mp4", {
+							type: 'video/mp4',
+						});
+					// console.log(file, 'file')
+					var videoUrl = await this.$method.uploadFileH5(file, 6, {
+						gradeId: this.gradeId,
+						orderGoodsId: this.orderGoodsId,
+					}, "video");
+				} catch (err) {
+					console.log(err, "err");
+					uni.showToast({
+						title: "上传接口报错,请重新录制上传",
+						icon: "none",
+						duration: 2000,
+					});
+					setTimeout(() => {
+						this.showMedia = true;
+					}, 1500);
+					return;
+				}
+				this.showMedia = false;
+				this.postCourseVideoRecord(videoUrl)
+					.then(async (res) => {
+						this.needtoTakeVideo = false;
+						if (this.curPlayOver) {
+							await this.ended();
+						}
+						//恢复播放
+						if (this.viewSign == 2) {
+							var polyvPlayerContext = this.player_tencent;
+							if (polyvPlayerContext && this.openPhotoStatus !== 1) {
+								polyvPlayerContext.play();
+							}
+						} else {
+							var polyvPlayerContext = this.player;
+							if (polyvPlayerContext && this.openPhotoStatus !== 1) {
+								polyvPlayerContext.j2s_resumeVideo();
+							}
+						}
+					})
+					.catch((err) => {
+						console.log(err, "err");
+						uni.showToast({
+							title: "上传接口报错,请重新录制上传",
+							icon: "none",
+							duration: 2000,
+						});
+						setTimeout(() => {
+							this.showMedia = true;
+						}, 1500);
+					});
+			},
 		},
 		provide() {
 			return {

+ 122 - 4
pages4/login/login.vue

@@ -21,7 +21,7 @@
 					<u-form-item prop="code" v-if="isDualAuth">
 						<u-input v-model="form.code" type="number" placeholder-style="color:#999999"
 							placeholder="验证码" />
-						<u-button slot="right" size="mini" @click="getCode('account')">{{
+						<u-button slot="right" size="mini" @click="getCodepre('account')">{{
               codeTips
             }}</u-button>
 					</u-form-item>
@@ -32,7 +32,7 @@
 					<u-form-item prop="code">
 						<u-input v-model="form.code" type="number" placeholder-style="color:#999999"
 							placeholder="验证码" />
-						<u-button slot="right" size="mini" @click="getCode('tel')">{{
+						<u-button slot="right" size="mini" @click="getCodepre('tel')">{{
               codeTips
             }}</u-button>
 					</u-form-item>
@@ -81,6 +81,19 @@
 			<!-- #endif -->
 		</view>
 		<u-verification-code seconds="60" ref="uCode" @change="codeChange"></u-verification-code>
+		<u-popup v-model="codeModal" :mask-close-able="false" closeable mode="center" width="80%" border-radius="24">
+			<view class="rf-popup-main">
+				<view class="title">获取手机验证码</view>
+				<u-form >
+					<u-form-item prop="imageCode">
+								<u-input v-model="imageCode" type="number" placeholder-style="color:#999999"
+									placeholder="图形验证码" />
+							 <image slot="right" style="width: 212rpx;height: 80rpx;margin-bottom: 40rpx;"  :src="codeUrl" @click="getCodepre"></image>
+							 </u-form-item>
+				</u-form>
+				<u-button type="primary" style="border-radius: 60rpx;" @click="getCode">获取手机验证码</u-button>
+			</view>
+		</u-popup>
 	</view>
 </template>
 
@@ -99,6 +112,11 @@ hF6WiNlWfQTVoF1rhwIDAQAB
 		data() {
 			return {
 				code: "",
+				codeModal: false,
+				imageCode:"",
+				imageUuid:"",
+				codeUrl:"",
+				telform:"tel",
 				form: {
 					tel: "",
 					code: "",
@@ -416,17 +434,44 @@ hF6WiNlWfQTVoF1rhwIDAQAB
 			codeChange(text) {
 				this.codeTips = text;
 			},
+			//获取图形验证码
+			getCodepre(key){
+				this.codeModal=true;
+				this.telform=key;
+				this.$api.captchaImage({}).then(
+					(res) => {
+						if (res.data.code == 200) {
+							this.codeUrl = "data:image/gif;base64," + res.data.data.img;
+							this.imageUuid= res.data.data.uuid;
+						} else {
+							this.$u.toast(res.data.msg);
+						}
+					},
+					(err) => {
+						console.log(err);
+					}
+				);
+			},
 			// 获取验证码
-			getCode(key) {
+			getCode() {
 				let that = this;
+				var key=this.telform;
+				if(!this.imageCode)
+				{
+					that.$u.toast("请输入图形验证码");
+					return;
+				}
 				if (that.$refs.uCode.canGetCode) {
 					if (that.$refs[key].validateState == "success") {
 						let datas = {
-							tel: this.form[key]
+							tel: this.form[key],
+							imageCode:this.imageCode,
+							imageUuid:this.imageUuid
 						};
 						that.$api.loginSms(datas).then(
 							(res) => {
 								if (res.data.code == 200) {
+									this.codeModal=false;
 									that.$u.toast("验证码已发送");
 									// 通知验证码组件内部开始倒计时
 									that.$refs.uCode.start();
@@ -548,6 +593,54 @@ hF6WiNlWfQTVoF1rhwIDAQAB
 								userId: resdata.data.data.userId,
 							});
 						}
+						
+						if(res.data.data.pwd_sign==1)
+						{
+							uni.showModal({
+								title: '温馨提示',
+								content: "您的密码已长时间未变更,为了您的账号安全,请前往更改密码。",
+								confirmText: "前往",
+								success: (result) => {
+									if (result.confirm) {
+										uni.navigateTo({
+											url: "/pages2/wd/pwd",
+										});
+									} else if (result.cancel) {
+										if (!this.isBack) {
+											let goPath = "";
+											if (types == "wxlogin" || types == "smslogin") {
+												//密码登录不用判断电脑goPath, 直接到首页
+												goPath = uni.getStorageSync("goPath");
+											}
+											if (goPath == "course") {
+												uni.redirectTo({
+													url: "/pages2/wd/class",
+												});
+												types == "wxlogin" &&
+													this.$method.setUuid(new Date().valueOf() + "");
+											} else if (goPath == "bank") {
+												uni.redirectTo({
+													url: "/pages2/wd/question_bank",
+												});
+												types == "wxlogin" &&
+													this.$method.setUuid(new Date().valueOf() + "");
+											} else {
+												console.log("登录后跳转");
+												uni.removeStorageSync("h5_code");
+												uni.reLaunch({
+													url: "/pages/index/index?show=1",
+												});
+												types == "wxlogin" &&
+													this.$method.setUuid(new Date().valueOf() + "");
+											}
+										} else {
+											uni.navigateBack();
+										}
+									}
+								}
+							});
+							return
+						}
 						//
 						if (!this.isBack) {
 							let goPath = "";
@@ -724,4 +817,29 @@ hF6WiNlWfQTVoF1rhwIDAQAB
 		position: absolute;
 		left: 30rpx;
 	}
+	.rf-popup-main {
+		text-align: center;
+		padding: 40rpx;
+	
+		.title {
+			font-size: 40rpx;
+			font-weight: 600;
+		}
+	
+		.tip {
+			margin: 30rpx 0 40rpx;
+			font-size: 32rpx;
+		}
+	
+		.u-input {
+			border-radius: 20rpx;
+			background: #eee;
+			padding-left: 20rpx !important;
+			margin-bottom: 40rpx;
+		}
+	
+		.u-button {
+			border-radius: 60rpx !important;
+		}
+	}
 </style>

+ 401 - 157
pages4/login/pcLogin.vue

@@ -1,164 +1,408 @@
 <template>
-  <view class="pcLogins">
-    <u-navbar
-      :is-back="false"
-      title="登录"
-      :border-bottom="false"
-      title-color="#333333"
-      back-icon-color="#ffffff"
-    >
-    </u-navbar>
-    <u-line color="#D6D6DB" />
-    <view class="contents">
-      <!-- 正文内容 -->
-      <image
-        class="logo"
-        :src="SCAN_LOGO"
-        style="width: 360rpx; height: 72rpx"
-      ></image>
-      <text>登录后您可在网页端继续浏览课程</text>
-      <!-- <view class="login_bt" @click="pcLogin()">微信登录</view> -->
-      <button
-        type="default"
-        open-type="getPhoneNumber"
-        @getphonenumber="wxLogin"
-        class="login_bt"
-      >
-        微信登录
-      </button>
-    </view>
-  </view>
+	<view class="pcLogins">
+		<u-navbar :is-back="false" title="登录" :border-bottom="false" title-color="#333333" back-icon-color="#ffffff">
+		</u-navbar>
+		<u-line color="#D6D6DB" />
+		<view class="contents">
+			<!-- 正文内容 -->
+			<image class="logo" :src="SCAN_LOGO" style="width: 360rpx; height: 72rpx"></image>
+			<text>登录后您可在网页端继续浏览课程</text>
+			<!-- #ifdef H5 -->
+			<view class="login_box" v-show="showinput">
+				<u-form :model="form" ref="uForm1">
+					<u-form-item prop="account"><u-input type="idcard" v-model="form.account"
+							placeholder-style="color:#999999" placeholder="手机号/学员身份证" /></u-form-item>
+					<u-form-item prop="pwd"><u-input class="password" v-model="form.pwd"
+							placeholder-style="color:#999999" type="password" placeholder="登录密码" /></u-form-item>
+
+				</u-form>
+			</view>
+			<view class="login_bt" @click="pcLogin()">微信登录</view>
+			<!-- #endif -->
+			<!-- #ifdef MP-WEIXIN -->
+			<button type="default" open-type="getPhoneNumber" @getphonenumber="wxLogin" class="login_bt">
+				微信登录
+			</button>
+			<!-- #endif -->
+		</view>
+	</view>
 </template>
 
 <script>
-import config from "@/common/config";
-export default {
-  data() {
-    return {
-      SCAN_LOGO: config.SCAN_LOGO,
-      scanCode: "", // 获取扫码的路径最后面的6位标识码
-      code: "",
-    };
-  },
-  onLoad(query) {
-    const q = decodeURIComponent(query.q);
-    this.scanCode = q.substring(q.length - 6);
-    console.log("扫描后得:", q, this.scanCode);
-    // 扫描二维码后调用,小程序已扫码
-    if (this.scanCode) {
-      this.$api.scanhasCode({ scanCode: this.scanCode }).then((res) => {
-        console.log("调用扫码接口返回的:", res);
-        if (res.data.code == 200) {
-          console.log();
-        }
-      });
-    }
-  },
-  onShow() {
-    // 获取code
-    this.getwxCode();
-  },
-  methods: {
-    getwxCode() {
-      uni.login({
-        provider: "weixin",
-        success: (loginRes) => {
-          this.code = loginRes.code;
-          console.log("获取的code:", this.code);
-        },
-      });
-    },
-    wxLogin(e) {
-      this.$api
-        .wxLogin({
-          code: this.code,
-          encryptedData: e.detail.encryptedData,
-          iv: e.detail.iv,
-        })
-        .then((res) => {
-          if (res.data.code == 200) {
-            this.loginCallback(res);
-          } else {
-            if (res.data.code == 666) {
-              this.$u.toast(res.data.msg); 
-              setTimeout(() => {
-                uni.navigateTo({
-                  url: "/pages2/register/register" ,
-                });
-              }, 500);
-              return;
-            }
-            this.getwxCode(); // code用完一次就会过期,防止用户点击取消后再点微信登录后code过期
-          }
-        });
-    },
-    // 微信登录成功的回调
-    loginCallback(res) {
-      // console.log('登录后的回调',res)
-      // if(res.data.data && res.data.data.full_info){
-      //信息完善,直接进入页面
-      uni.setStorageSync("user_account", res.data.data.user_account);
-      uni.setStorageSync("token", res.data.data.token);
-      // /app/user/getInfo 登录用户信息// fromPlat来源平台 1小程序 2PC网站
-      this.$api.getInfo({ fromPlat: 1 }).then((resdata) => {
-        if (resdata.data.code == 200) {
-          this.$store.state.userInfo = resdata.data.data;
-
-          this.submitCode();
-        }
-      });
-      // } else {
-      // 	//未完善信息,存为临时信息
-      // 	uni.setStorageSync('user_account_temp', res.data.data.user_account);
-      // 	uni.setStorageSync('token_temp', res.data.data.token);
-      //     this.$navTo.togo('/pages2/register/bind', {scanCode: this.scanCode})
-      // }
-    },
-    // scanLoginCheck小程序校验PC登录二维码,执行登录获取到令牌,然后把扫码的路径最后面的6位标识码提交给后台就行
-    submitCode() {
-      this.$api
-        .scanLoginCheck({
-          scanCode: this.scanCode,
-        })
-        .then((res) => {
-          if (res.data.code == 200) {
-            uni.navigateTo({
-              url: "/pages4/login/pcLoginSuccess",
-            });
-          } else {
-            this.$u.toast(res.data.msg);
-          }
-        });
-    },
-  },
-};
+	import configjs from "@/common/config";
+	import {
+		getCode
+	} from "@/utils/authority";
+	import {
+		mapGetters,
+		mapActions
+	} from "vuex";
+	export default {
+		data() {
+			return {
+				SCAN_LOGO: configjs.SCAN_LOGO,
+				scanCode: "", // 获取扫码的路径最后面的6位标识码
+				code: "sss",
+				gzhOpenid: "",
+				showinput: false,
+				isUse: false,
+				form: {
+					account: "",
+					pwd: "",
+				},
+				rules: {
+					account: [{
+						required: true,
+						message: "请输入手机号/学员身份证",
+						trigger: ["change"],
+					}, ],
+					pwd: [{
+						required: true,
+						message: "请输入密码",
+						// 可以单个或者同时写两个触发验证方式
+						trigger: ["change"],
+					}, ],
+				},
+			};
+		},
+		onLoad(query) {
+			console.log("扫描后得1:", query);
+			const q = decodeURIComponent(query.q);
+			if (query.acc && query.pwd) {
+				const acc = decodeURIComponent(query.acc);
+				const pwd = decodeURIComponent(query.pwd);
+				this.form.account = acc;
+				this.form.pwd = pwd;
+			}
+			this.scanCode = q.substring(q.length - 6);
+			console.log("扫描后得:", q, this.scanCode, this.form.account);
+			// 扫描二维码后调用,小程序已扫码
+			if (this.scanCode) {
+				this.$api.scanhasCode({
+					scanCode: this.scanCode
+				}).then((res) => {
+					console.log("调用扫码接口返回的:", res);
+					if (res.data.code == 200) {
+						console.log();
+					}
+				});
+			}
+			// 获取code
+			// #ifdef MP-WEIXIN
+			this.getwxCode();
+			// #endif
+			// #ifdef H5 
+			this.getWXCodeh5(1);
+
+			// #endif
+		},
+		onShow() {},
+		computed: {
+			...mapGetters(["config"]),
+		},
+		methods: {
+			topclogin() {
+				this.$api
+					.check_gzh_openId({
+						code: this.code,
+						account: this.form.account,
+						password: this.form.pwd,
+						gzhOpenid: this.gzhOpenid,
+					})
+					.then((res) => {
+						if (res.data.code == 200) {
+							if (res.data.data.gzhStatus == 1) {
+								this.loginCallback(res);
+							} else {
+								this.$u.toast("请输入账号密码绑定微信登录");
+								this.showinput = true;
+								if (res.data.data.gzhOpenid) {
+									this.gzhOpenid = res.data.data.gzhOpenid;
+								}
+								// this.getWXCodeh5(0);A
+							}
+						} else {
+							this.$u.toast(res.data.msg);
+							// this.getWXCodeh5(0);
+						}
+					});
+			},
+			pcLogin() {
+				let that = this;
+				if (this.showinput) {
+					if (!this.form.account) {
+						this.$u.toast("请输入手机号码/身份证号");
+						return;
+					}
+					if (!this.form.pwd) {
+						this.$u.toast("请输入密码");
+						return;
+					}
+				}
+				if (this.gzhOpenid) {
+					this.topclogin();
+				} else {
+					this.getWXCodeh5(0);
+				}
+			},
+			// 获取code并登录   
+			getWXCodeh5(totype) {
+				var code = this.getUrlCode().code; //是否存在code
+				if (code == this.code) {
+					code = '';
+				}
+				let url = location.href //授权后重定向的回调链接地址
+				let url2 = 'https://' + window.location.host + "/pages4/login/pcLogin?q=" + this.scanCode;
+				if (totype == 0) {
+					url2 = url2 + "&acc=" + this.form.account + "&pwd=" + this.form.pwd
+				}
+				console.log("dasdsada1", url2);
+				// let code =getCode(url2);
+				if (code == null || code === "") {
+					this.$api.mobileConfig().then((res0) => {
+						// console.log("res0",res0);
+					  	var gzhSelfLicense=false;
+						let data = res0.data.rows.find((e) => e.configKey == "home.mobile");
+						if (data) {
+							var config1 = JSON.parse(data.configValue) || {}
+							gzhSelfLicense=config1.gzhSelfLicense;
+							console.log('gzhSelfLicense',config1.gzhSelfLicense,gzhSelfLicense)
+						}
+					if (gzhSelfLicense) {
+						this.$api.getWxConfig().then((res) => {
+							console.log("res", res);
+							let appid = res.data.data.gzhAppId //公众号的唯一标识
+							window.location.replace('https://open.weixin.qq.com/connect/oauth2/authorize?appid=' +
+								appid + '&redirect_uri=' + encodeURIComponent(url2) +
+								'&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect')
+						});
+					} else {
+						url2 = url2.split("//")[1];
+						location.replace("https://www.xyyxt.net/home/index2?ask_type=" + url2);
+					}
+					});
+
+				} else {
+					this.code = code;
+					console.log("dasdsada2", this.code);
+					//此处调用后端提供的接口,传入获取到的code换取access_token
+					if (totype == 1) {
+						this.topclogin();
+					} else if (totype == 0) {
+						this.topclogin();
+					}
+				}
+				// this.$api.getWxConfig().then((res) => {
+				// 	console.log("res", res);
+				// 	let appid = res.data.data.gzhAppId //公众号的唯一标识
+
+				// });
+
+
+			},
+
+			// 截取url中的code方法
+			getUrlCode() {
+				// 截取url中的code方法
+				var url = location.search;
+				var theRequest = new Object();
+				if (url.indexOf("?") != -1) {
+					var str = url.substr(1);
+					var strs = str.split("&");
+					for (var i = 0; i < strs.length; i++) {
+						theRequest[strs[i].split("=")[0]] = strs[i].split("=")[1];
+					}
+				}
+				return theRequest;
+			},
+			getwxCode() {
+				uni.login({
+					provider: "weixin",
+					success: (loginRes) => {
+						this.code = loginRes.code;
+						console.log("获取的code:", this.code);
+					},
+					fail: (err) => {
+						// this.code = 'fff';
+						console.log(this.code)
+					},
+					complete: (com) => {
+						// this.code = 'ccc';
+						console.log(this.code)
+					},
+				});
+			},
+			wxLogin(e) {
+				this.$api
+					.wxLogin({
+						code: this.code,
+						encryptedData: e.detail.encryptedData,
+						iv: e.detail.iv,
+					})
+					.then((res) => {
+						if (res.data.code == 200) {
+							this.loginCallback(res);
+						} else {
+							if (res.data.code == 666) {
+								this.$u.toast(res.data.msg);
+								setTimeout(() => {
+									uni.navigateTo({
+										url: "/pages2/register/register",
+									});
+								}, 500);
+								return;
+							}
+							this.getwxCode(); // code用完一次就会过期,防止用户点击取消后再点微信登录后code过期
+						}
+					});
+			},
+			// 微信登录成功的回调
+			loginCallback(res) {
+				// console.log('登录后的回调',res)
+				// if(res.data.data && res.data.data.full_info){
+				//信息完善,直接进入页面
+				uni.setStorageSync("user_account", res.data.data.user_account);
+				uni.setStorageSync("token", res.data.data.token);
+				// /app/user/getInfo 登录用户信息// fromPlat来源平台 1小程序 2PC网站
+				this.$api.getInfo({
+					fromPlat: 1
+				}).then((resdata) => {
+					if (resdata.data.code == 200) {
+						this.$store.state.userInfo = resdata.data.data;
+
+						this.submitCode();
+					}
+				});
+				// } else {
+				// 	//未完善信息,存为临时信息
+				// 	uni.setStorageSync('user_account_temp', res.data.data.user_account);
+				// 	uni.setStorageSync('token_temp', res.data.data.token);
+				//     this.$navTo.togo('/pages2/register/bind', {scanCode: this.scanCode})
+				// }
+			},
+			// scanLoginCheck小程序校验PC登录二维码,执行登录获取到令牌,然后把扫码的路径最后面的6位标识码提交给后台就行
+			submitCode() {
+				this.$api
+					.scanLoginCheck({
+						scanCode: this.scanCode,
+					})
+					.then((res) => {
+						if (res.data.code == 200) {
+							uni.navigateTo({
+								url: "/pages4/login/pcLoginSuccess",
+							});
+						} else {
+							this.$u.toast(res.data.msg);
+						}
+					});
+			},
+			pwlogin() {
+				let that = this;
+				if (!this.form.account) {
+					this.$u.toast("请输入手机号码/身份证号");
+					return;
+				}
+				if (!this.form.pwd) {
+					this.$u.toast("请输入密码");
+					return;
+				}
+
+
+				//虚拟登录
+				/* that.fakeLogin()
+	return */
+				that.isUse = true;
+				let form = JSON.parse(JSON.stringify(this.form));
+				form.pwd = this.encryptor(form.pwd);
+				form["shareActivityCode"] = this.shareActivityCode;
+				// 账号登录用户 /app/common/account_login
+				that.$api.accountLogin(form).then(
+					(res) => {
+						that.isUse = false;
+						if (res.data.code == 200) {
+							this.loginCallback(res, "pwlogin");
+						} else if (res.data.code == 699) {
+							uni.showModal({
+								title: '温馨提示',
+								content: "系统升级中,请点击按钮 “复制” 链接,打开手机浏览器,粘贴登录即可学习",
+								confirmText: "复制",
+								success: (result) => {
+									if (result.confirm) {
+										uni.setClipboardData({
+											data: res.data.msg,
+											success: function() {
+												uni.showToast({
+													title: '链接已复制成功',
+													icon: 'none',
+													duration: 2000
+												});
+											}
+										})
+									} else if (result.cancel) {
+										console.log('用户点击取消');
+									}
+								}
+							});
+						} else {
+							that.$u.toast(res.data.msg);
+						}
+					},
+					(err) => {
+						that.isUse = false;
+					}
+				);
+			},
+		},
+	};
 </script>
 
 <style lang="scss" scoped>
-.contents {
-  width: 100%;
-  height: 100%;
-  text-align: center;
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  .logo {
-    margin: 90rpx 0rpx 250rpx;
-  }
-  > text {
-    font-size: 22rpx;
-    color: #666;
-  }
-  .login_bt {
-    width: 400rpx;
-    height: 70rpx;
-    line-height: 70rpx;
-    text-align: center;
-    background: #09ba08;
-    color: #fff;
-    font-size: 28rpx;
-    border-radius: 35rpx;
-    margin-top: 20rpx;
-  }
-}
-</style>
+	.contents {
+		width: 100%;
+		height: 100%;
+		text-align: center;
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+
+		.logo {
+			margin: 90rpx 0rpx 250rpx;
+		}
+
+		>text {
+			font-size: 22rpx;
+			color: #666;
+		}
+
+		.login_bt {
+			width: 400rpx;
+			height: 70rpx;
+			line-height: 70rpx;
+			text-align: center;
+			background: #09ba08;
+			color: #fff;
+			font-size: 28rpx;
+			border-radius: 35rpx;
+			margin-top: 20rpx;
+		}
+	}
+
+	.login_box {
+		width: 80%;
+		height: 360rpx;
+		background: #ffffff;
+		box-shadow: 0rpx 0rpx 16rpx 4rpx rgba(1, 99, 235, 0.1);
+		border-radius: 24rpx;
+		margin-top: 30rpx;
+		padding: 40rpx 35rpx;
+
+		.password {
+			/deep/.uicon-eye-fill {
+				&::before {
+					color: #007aff;
+					content: "\e613";
+				}
+			}
+		}
+	}
+</style>