专家人脸登录开发完成
This commit is contained in:
@ -55,7 +55,11 @@
|
|||||||
// });
|
// });
|
||||||
|
|
||||||
function receiveMessageFromParent ( event ) {
|
function receiveMessageFromParent ( event ) {
|
||||||
webcam.capture();
|
if(event.data == 'releaseCamera'){
|
||||||
|
location.reload();
|
||||||
|
}else if(event.data = 'capture'){
|
||||||
|
webcam.capture();
|
||||||
|
}
|
||||||
//$('#base64image').attr('src', 'data:image/jpg;base64,' + event.data.data);
|
//$('#base64image').attr('src', 'data:image/jpg;base64,' + event.data.data);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, { useEffect, useState, useRef } from 'react';
|
import React, { useEffect, useState, useRef } from 'react';
|
||||||
import { Form, Button, Input, Row, Col, Modal, Spin, message } from 'antd';
|
import { Form, Button, Input, Row, Col, Modal, Spin, message, Tabs } from 'antd';
|
||||||
import { UserOutlined, LockOutlined, SafetyCertificateOutlined, VideoCameraOutlined } from '@ant-design/icons';
|
import { UserOutlined, LockOutlined, SafetyCertificateOutlined, VideoCameraOutlined } from '@ant-design/icons';
|
||||||
import './style.less';
|
import './style.less';
|
||||||
import { changePass, rgbToBase64 } from './service';
|
import { changePass, rgbToBase64 } from './service';
|
||||||
@ -23,15 +23,19 @@ export interface RgbParams {
|
|||||||
|
|
||||||
const Index: React.FC<{}> = () => {
|
const Index: React.FC<{}> = () => {
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
|
const [form2] = Form.useForm();
|
||||||
const [imgUrl, setImgUrl] = useState<any>('');
|
const [imgUrl, setImgUrl] = useState<any>('');
|
||||||
const [tmpToken, setTmpToken] = useState<any>('');
|
const [tmpToken, setTmpToken] = useState<any>('');
|
||||||
const remainingTime = 3 //刷新token的剩余时间,单位小时
|
const remainingTime = 3 //刷新token的剩余时间,单位小时
|
||||||
const [changeForm] = Form.useForm();
|
const [changeForm] = Form.useForm();
|
||||||
const [isModalVisible, setIsModalVisible] = useState<boolean>(false)
|
const [isModalVisible, setIsModalVisible] = useState<boolean>(false)
|
||||||
const [spinning, setSping] = useState<boolean>(false);//加载遮罩
|
const [spinning, setSping] = useState<boolean>(false);//加载遮罩
|
||||||
const [isFaceLogin, setIsFaceLogin] = useState<boolean>(false);
|
|
||||||
const video = useRef();
|
const video = useRef();
|
||||||
const whetherIE = useRef<boolean>(false);
|
const whetherIE = useRef<boolean>(false);
|
||||||
|
const mediaStreamTrack = useRef<any>();
|
||||||
|
const { TabPane } = Tabs;
|
||||||
|
const [submitLoading, setSubmitLoading] = useState<boolean>(false);
|
||||||
|
const [faceLoginDisable, setFaceLoginDisable] = useState<boolean>(false);
|
||||||
|
|
||||||
const genRandomString = (len: number) => {
|
const genRandomString = (len: number) => {
|
||||||
const text = 'abcdefghijklmnopqrstuvwxyz0123456789';
|
const text = 'abcdefghijklmnopqrstuvwxyz0123456789';
|
||||||
@ -84,8 +88,28 @@ const Index: React.FC<{}> = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onChange = (key: string) => {
|
||||||
|
if(key == '2'){
|
||||||
|
BrowserType();
|
||||||
|
InitMedia();
|
||||||
|
}else{
|
||||||
|
if(allowedToFaceLogin()){
|
||||||
|
if(whetherIE.current){
|
||||||
|
releaseCamera('faceLoginFrame');
|
||||||
|
}else{
|
||||||
|
mediaStreamTrack.current?.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const releaseCamera = (id:string) => {
|
||||||
|
const childFrameObj = document.getElementById(id);
|
||||||
|
childFrameObj?.contentWindow?.postMessage('releaseCamera', '*');
|
||||||
|
}
|
||||||
|
|
||||||
const hanleFaceSubmit = async (multipartFiles: any, values: any) => {
|
const hanleFaceSubmit = async (multipartFiles: any, values: any) => {
|
||||||
let userName = form.getFieldValue('userName');
|
let userName = form2.getFieldValue('userName');
|
||||||
if(whetherIE.current){
|
if(whetherIE.current){
|
||||||
if(!multipartFiles){
|
if(!multipartFiles){
|
||||||
const childFrameObj = document.getElementById('faceLoginFrame');
|
const childFrameObj = document.getElementById('faceLoginFrame');
|
||||||
@ -96,13 +120,17 @@ const Index: React.FC<{}> = () => {
|
|||||||
if (moment(res?.data?.expiration).diff(moment(), 'hours') < remainingTime) {
|
if (moment(res?.data?.expiration).diff(moment(), 'hours') < remainingTime) {
|
||||||
refreshToken(res?.data)
|
refreshToken(res?.data)
|
||||||
} else {
|
} else {
|
||||||
|
releaseCamera('faceLoginFrame');
|
||||||
sessionStorage.setItem('Authorization', res?.data?.value);
|
sessionStorage.setItem('Authorization', res?.data?.value);
|
||||||
sessionStorage.setItem('refreshToken', res?.data?.refreshToken.value);
|
sessionStorage.setItem('refreshToken', res?.data?.refreshToken.value);
|
||||||
sessionStorage.setItem('scope', res?.data?.scope);
|
sessionStorage.setItem('scope', res?.data?.scope);
|
||||||
history.push('/redirect');
|
history.push('/redirect');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
.finally(
|
||||||
|
() => {setSubmitLoading(false);}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
@ -116,18 +144,23 @@ const Index: React.FC<{}> = () => {
|
|||||||
hanleFaceSubmit(result, null);
|
hanleFaceSubmit(result, null);
|
||||||
})
|
})
|
||||||
}else{
|
}else{
|
||||||
|
setSubmitLoading(true);
|
||||||
await ZjfakeFaceLogin({ userName, multipartFiles }).then((res) => {
|
await ZjfakeFaceLogin({ userName, multipartFiles }).then((res) => {
|
||||||
if (res?.success) {
|
if (res?.success) {
|
||||||
if (moment(res?.data?.expiration).diff(moment(), 'hours') < remainingTime) {
|
if (moment(res?.data?.expiration).diff(moment(), 'hours') < remainingTime) {
|
||||||
refreshToken(res?.data)
|
refreshToken(res?.data)
|
||||||
} else {
|
} else {
|
||||||
|
mediaStreamTrack.current?.stop();
|
||||||
sessionStorage.setItem('Authorization', res?.data?.value);
|
sessionStorage.setItem('Authorization', res?.data?.value);
|
||||||
sessionStorage.setItem('refreshToken', res?.data?.refreshToken.value);
|
sessionStorage.setItem('refreshToken', res?.data?.refreshToken.value);
|
||||||
sessionStorage.setItem('scope', res?.data?.scope);
|
sessionStorage.setItem('scope', res?.data?.scope);
|
||||||
history.push('/redirect');
|
history.push('/redirect');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
.finally(
|
||||||
|
() => {setSubmitLoading(false);}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -158,19 +191,6 @@ const Index: React.FC<{}> = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//登录模式改变事件
|
|
||||||
const LoginModeChangeEvent = (mode: any) => {
|
|
||||||
switch(mode){
|
|
||||||
case 1:
|
|
||||||
setIsFaceLogin(true);
|
|
||||||
InitMedia();
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
setIsFaceLogin(false);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//浏览器类型
|
//浏览器类型
|
||||||
const BrowserType = () =>{
|
const BrowserType = () =>{
|
||||||
//取得浏览器的userAgent字符串
|
//取得浏览器的userAgent字符串
|
||||||
@ -210,7 +230,6 @@ const Index: React.FC<{}> = () => {
|
|||||||
}
|
}
|
||||||
//初始化video
|
//初始化video
|
||||||
const InitMedia = () => {
|
const InitMedia = () => {
|
||||||
BrowserType();
|
|
||||||
if(!whetherIE.current){
|
if(!whetherIE.current){
|
||||||
InitUserMedia({video : {width: 480, height: 320}}, success, error);
|
InitUserMedia({video : {width: 480, height: 320}}, success, error);
|
||||||
}
|
}
|
||||||
@ -233,13 +252,19 @@ const Index: React.FC<{}> = () => {
|
|||||||
}
|
}
|
||||||
//调用媒体设备成功回调方法
|
//调用媒体设备成功回调方法
|
||||||
const success = (stream: any) => {
|
const success = (stream: any) => {
|
||||||
//兼容webkit核心浏览器
|
var result = stream.getVideoTracks().some(function(track:any) {
|
||||||
const CompatibleURL = window.URL || window.webkitURL;
|
return track.enabled && track.readyState === 'live';
|
||||||
//将视频流设置为video元素的源
|
});
|
||||||
console.log(stream);
|
if (result) {
|
||||||
//video.src = CompatibleURL.createObjectURL(stream);
|
//兼容webkit核心浏览器
|
||||||
video.current.srcObject = stream;
|
const CompatibleURL = window.URL || window.webkitURL;
|
||||||
video.current.play();
|
//将视频流设置为video元素的源
|
||||||
|
console.log(stream);
|
||||||
|
//video.src = CompatibleURL.createObjectURL(stream);
|
||||||
|
video.current.srcObject = stream;
|
||||||
|
mediaStreamTrack.current = stream.getTracks()[0];
|
||||||
|
video.current.play();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//调用媒体设备失败回调方法
|
//调用媒体设备失败回调方法
|
||||||
const error = (error:any) => {
|
const error = (error:any) => {
|
||||||
@ -262,16 +287,46 @@ const Index: React.FC<{}> = () => {
|
|||||||
|
|
||||||
//RgbToBase64
|
//RgbToBase64
|
||||||
const RgbToBase64 = async (image:any) =>{
|
const RgbToBase64 = async (image:any) =>{
|
||||||
|
setSubmitLoading(true);
|
||||||
await rgbToBase64({image}).then(res => {
|
await rgbToBase64({image}).then(res => {
|
||||||
const _blob = base64ToBlob( 'data:image/jpg;base64,' + res.data);
|
const _blob = base64ToBlob( 'data:image/jpg;base64,' + res.data);
|
||||||
hanleFaceSubmit(_blob, null);
|
hanleFaceSubmit(_blob, null);
|
||||||
|
}).catch(e=>{
|
||||||
|
setSubmitLoading(false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//是https或者是本地
|
||||||
|
const httpsOrLocal = () => {
|
||||||
|
let protocol = document.location.protocol;
|
||||||
|
if(protocol == 'https'){
|
||||||
|
return true;
|
||||||
|
}else{
|
||||||
|
let host = window.location.hostname;
|
||||||
|
if(host == '127.0.0.1' || host == 'localhost'){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//是否允许人脸登录
|
||||||
|
const allowedToFaceLogin = () => {
|
||||||
|
let browseType = BrowserType()
|
||||||
|
if((browseType == 11 || browseType == -1) && httpsOrLocal()){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
cookie.remove('mall3_token');
|
cookie.remove('mall3_token');
|
||||||
sessionStorage.clear();
|
sessionStorage.clear();
|
||||||
changeCaptcha();
|
changeCaptcha();
|
||||||
|
if(!allowedToFaceLogin()){
|
||||||
|
setFaceLoginDisable(true);
|
||||||
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -284,109 +339,110 @@ const Index: React.FC<{}> = () => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="main">
|
<div className="main">
|
||||||
<div className="text">
|
<div className="text">
|
||||||
<h3>登 录</h3>
|
<Tabs defaultActiveKey="1" onChange={onChange} size = {'large'}>
|
||||||
{!isFaceLogin ? (
|
<TabPane tab="账号密码登录" key="1">
|
||||||
<Form
|
<Form
|
||||||
name="basic"
|
name="basic"
|
||||||
className="form-box"
|
className="form-box"
|
||||||
initialValues={{ remember: true }}
|
initialValues={{ remember: true }}
|
||||||
form={form}
|
form={form}
|
||||||
onFinish={handleSubmit}
|
onFinish={handleSubmit}
|
||||||
// onFinishFailed={onFinishFailed}
|
// onFinishFailed={onFinishFailed}
|
||||||
>
|
>
|
||||||
<Form.Item
|
|
||||||
label=""
|
|
||||||
name="userName"
|
|
||||||
rules={[{ required: true, message: '请输入用户名!' }]}
|
|
||||||
>
|
|
||||||
<Input
|
|
||||||
prefix={
|
|
||||||
<UserOutlined style={{ fontSize: '18px' }} className="site-form-item-icon" />
|
|
||||||
}
|
|
||||||
placeholder="请输入用户名"
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item
|
|
||||||
label=""
|
|
||||||
name="password"
|
|
||||||
rules={[{ required: true, message: '请输入密码!' }]}
|
|
||||||
>
|
|
||||||
<Input.Password
|
|
||||||
prefix={
|
|
||||||
<LockOutlined style={{ fontSize: '18px' }} className="site-form-item-icon" />
|
|
||||||
}
|
|
||||||
placeholder="请输入密码"
|
|
||||||
addonAfter={<VideoCameraOutlined onClick={() => LoginModeChangeEvent(1)}/>}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Row>
|
|
||||||
<Col span={14}>
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label=""
|
label=""
|
||||||
name="captcha"
|
name="userName"
|
||||||
rules={[{ required: true, message: '请输入验证码!' }]}
|
rules={[{ required: true, message: '请输入用户名!' }]}
|
||||||
>
|
>
|
||||||
<Input
|
<Input
|
||||||
prefix={
|
prefix={
|
||||||
<SafetyCertificateOutlined
|
<UserOutlined style={{ fontSize: '18px' }} className="site-form-item-icon" />
|
||||||
style={{ fontSize: '18px' }}
|
|
||||||
className="site-form-item-icon"
|
|
||||||
/>
|
|
||||||
}
|
}
|
||||||
placeholder="请输入验证码"
|
placeholder="请输入用户名"
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
label=""
|
||||||
|
name="password"
|
||||||
|
rules={[{ required: true, message: '请输入密码!' }]}
|
||||||
|
>
|
||||||
|
<Input.Password
|
||||||
|
prefix={
|
||||||
|
<LockOutlined style={{ fontSize: '18px' }} className="site-form-item-icon" />
|
||||||
|
}
|
||||||
|
placeholder="请输入密码"
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
|
||||||
<Col span={10}>
|
|
||||||
<img className="verification" onClick={() => changeCaptcha()} src={imgUrl} />
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
|
|
||||||
{/* <Form.Item className="remember" name="remember" valuePropName="checked">
|
<Row>
|
||||||
<Checkbox>记住密码</Checkbox>
|
<Col span={14}>
|
||||||
</Form.Item> */}
|
<Form.Item
|
||||||
<Form.Item>
|
label=""
|
||||||
<Button type="primary" className="w100" htmlType="submit">
|
name="captcha"
|
||||||
登 录
|
rules={[{ required: true, message: '请输入验证码!' }]}
|
||||||
</Button>
|
>
|
||||||
</Form.Item>
|
<Input
|
||||||
</Form>):(
|
prefix={
|
||||||
<Form
|
<SafetyCertificateOutlined
|
||||||
name="basic"
|
style={{ fontSize: '18px' }}
|
||||||
className="form-box"
|
className="site-form-item-icon"
|
||||||
initialValues={{ remember: true }}
|
/>
|
||||||
form={form}
|
}
|
||||||
onFinish={hanleFaceSubmit.bind(this, null)}
|
placeholder="请输入验证码"
|
||||||
// onFinishFailed={onFinishFailed}
|
/>
|
||||||
>
|
</Form.Item>
|
||||||
<Form.Item
|
</Col>
|
||||||
label=""
|
<Col span={10}>
|
||||||
name="userName"
|
<img className="verification" onClick={() => changeCaptcha()} src={imgUrl} />
|
||||||
rules={[{ required: true, message: '请输入用户名!' }]}
|
</Col>
|
||||||
>
|
</Row>
|
||||||
<Input
|
|
||||||
prefix={
|
{/* <Form.Item className="remember" name="remember" valuePropName="checked">
|
||||||
<UserOutlined style={{ fontSize: '18px' }} className="site-form-item-icon" />
|
<Checkbox>记住密码</Checkbox>
|
||||||
}
|
</Form.Item> */}
|
||||||
placeholder="请输入用户名"
|
<Form.Item>
|
||||||
addonAfter = {<LockOutlined onClick={() => LoginModeChangeEvent(2)}/>}
|
<Button type="primary" className="w100" htmlType="submit">
|
||||||
/>
|
登 录
|
||||||
</Form.Item>
|
</Button>
|
||||||
{/* 加载摄像头 */}
|
</Form.Item>
|
||||||
<Form.Item>
|
</Form>
|
||||||
{!whetherIE.current ? (<video ref={video} width="382" height="200"></video>):(<FrameFaceLogin faceCompareEvent = {RgbToBase64}/>)}
|
</TabPane>
|
||||||
</Form.Item>
|
<TabPane tab="人脸识别登录" key="2" disabled = {faceLoginDisable}>
|
||||||
<Form.Item>
|
<Form
|
||||||
{/* onClick={() => {hanleFaceSubmit(null, null);}} */}
|
name="basic2"
|
||||||
<Button type="primary" className="w100" htmlType="submit">
|
className="form-box"
|
||||||
登 录
|
initialValues={{ remember: true }}
|
||||||
</Button>
|
form={form2}
|
||||||
</Form.Item>
|
onFinish={hanleFaceSubmit.bind(this, null)}
|
||||||
</Form>)}
|
// onFinishFailed={onFinishFailed}
|
||||||
|
>
|
||||||
|
<Form.Item
|
||||||
|
label=""
|
||||||
|
name="userName"
|
||||||
|
rules={[{ required: true, message: '请输入用户名!' }]}
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
prefix={
|
||||||
|
<UserOutlined style={{ fontSize: '18px' }} className="site-form-item-icon" />
|
||||||
|
}
|
||||||
|
placeholder="请输入用户名"
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
{/* 加载摄像头 */}
|
||||||
|
<Form.Item>
|
||||||
|
{!whetherIE.current ? (<video ref={video} width="382" height="200"></video>):(<FrameFaceLogin faceCompareEvent = {RgbToBase64}/>)}
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item>
|
||||||
|
{/* onClick={() => {hanleFaceSubmit(null, null);}} */}
|
||||||
|
<Button type="primary" className="w100" loading = {submitLoading} htmlType="submit">
|
||||||
|
登 录
|
||||||
|
</Button>
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
</TabPane>
|
||||||
|
</Tabs>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* <div className="footer">版权所有:中国联合网络通信有限公司</div> */}
|
|
||||||
<Modal
|
<Modal
|
||||||
title="修改密码"
|
title="修改密码"
|
||||||
visible={isModalVisible}
|
visible={isModalVisible}
|
||||||
|
Reference in New Issue
Block a user