Files
fe_service_ebtp_frontend/src/pages/userformal/login/index.tsx

514 lines
18 KiB
TypeScript
Raw Normal View History

2022-08-17 17:21:01 +08:00
import React, { useEffect, useState, useRef } from 'react';
2022-03-10 14:24:13 +08:00
import { Form, Button, Input, Row, Col, Modal, Spin, message } from 'antd';
2022-08-17 17:21:01 +08:00
import { UserOutlined, LockOutlined, SafetyCertificateOutlined, VideoCameraOutlined } from '@ant-design/icons';
2022-03-10 14:24:13 +08:00
import './style.less';
2022-09-02 16:10:56 +08:00
import { changePass, rgbToBase64 } from './service';
2022-03-10 14:24:13 +08:00
import logo from '@/images/login/logoPic.png';
2022-09-02 16:10:56 +08:00
import { refreshTokenApi, ZjfakeAccountLogin, ZjfakeFaceLogin } from '@/services/login';
2022-03-10 14:24:13 +08:00
import { history } from 'umi';
import cookie from 'react-cookies';
import moment from 'moment';
2022-08-17 17:21:01 +08:00
import FrameFaceLogin from '../faceLogin/FrameFaceLogin';
2022-09-02 16:10:56 +08:00
import { fromPairs } from 'lodash';
2022-03-10 14:24:13 +08:00
const layout = {
labelCol: { span: 7 },
wrapperCol: { span: 13 },
};
2022-09-02 16:10:56 +08:00
export interface RgbParams {
type: string;
image: string;
}
2022-03-10 14:24:13 +08:00
const Index: React.FC<{}> = () => {
const [form] = Form.useForm();
const [imgUrl, setImgUrl] = useState<any>('');
const [tmpToken, setTmpToken] = useState<any>('');
const remainingTime = 3 //刷新token的剩余时间单位小时
const [changeForm] = Form.useForm();
const [isModalVisible, setIsModalVisible] = useState<boolean>(false)
const [spinning, setSping] = useState<boolean>(false);//加载遮罩
2022-08-17 17:21:01 +08:00
const [isFaceLogin, setIsFaceLogin] = useState<boolean>(false);
const video = useRef();
const whetherIE = useRef<boolean>(false);
2022-03-10 14:24:13 +08:00
const genRandomString = (len: number) => {
const text = 'abcdefghijklmnopqrstuvwxyz0123456789';
const rdmIndex = (text: string | any[]) => (Math.random() * text.length) | 0;
let rdmString = '';
for (; rdmString.length < len; rdmString += text.charAt(rdmIndex(text)));
return rdmString;
};
const changeCaptcha = () => {
let tmpToken = genRandomString(16);
let url = '/api/auth/captcha?token=' + tmpToken;
setTmpToken(tmpToken);
setImgUrl(url);
};
//登录刷新Token方法
const refreshToken = async (data: any) => {
const params = {
grant_type: "refresh_token",
refresh_token: data?.refreshToken?.value,
client_id: REACT_APP_CLIENT_KEY,
client_secret: REACT_APP_CLIENT_SECRET,
}
const header = {
clientId: REACT_APP_CLIENT_KEY,
}
await refreshTokenApi(params, header).then(res => {
if (res?.success == true) {
sessionStorage.setItem('Authorization', res?.data?.value);
sessionStorage.setItem('refreshToken', res?.data?.refreshToken.value);
sessionStorage.setItem('scope', res?.data?.scope);
history.push('/redirect');
}
})
}
const handleSubmit = async (values: any) => {
await ZjfakeAccountLogin({ ...values, tmpToken }).then((res) => {
if (res?.success) {
if (moment(res?.data?.expiration).diff(moment(), 'hours') < remainingTime) {
refreshToken(res?.data)
} else {
sessionStorage.setItem('Authorization', res?.data?.value);
sessionStorage.setItem('refreshToken', res?.data?.refreshToken.value);
sessionStorage.setItem('scope', res?.data?.scope);
history.push('/redirect');
}
}
changeCaptcha();
});
};
2022-09-02 16:10:56 +08:00
const hanleFaceSubmit = async (multipartFiles: any, values: any) => {
let userName = form.getFieldValue('userName');
if(whetherIE.current){
if(!multipartFiles){
const childFrameObj = document.getElementById('faceLoginFrame');
childFrameObj.contentWindow.postMessage('capture', '*');
}else{
await ZjfakeFaceLogin({ userName, multipartFiles }).then((res) => {
if (res?.success) {
if (moment(res?.data?.expiration).diff(moment(), 'hours') < remainingTime) {
refreshToken(res?.data)
} else {
sessionStorage.setItem('Authorization', res?.data?.value);
sessionStorage.setItem('refreshToken', res?.data?.refreshToken.value);
sessionStorage.setItem('scope', res?.data?.scope);
history.push('/redirect');
}
}
});
}
}
else{
if(!multipartFiles){
const canvas = document.createElement('canvas');
canvas.setAttribute('width','300');
canvas.setAttribute('height', '200');
const context = canvas.getContext('2d');
context.drawImage(video.current, 0, 0, 300, 200);
canvas.toBlob(function (result:any) {
hanleFaceSubmit(result, null);
})
}else{
await ZjfakeFaceLogin({ userName, multipartFiles }).then((res) => {
if (res?.success) {
if (moment(res?.data?.expiration).diff(moment(), 'hours') < remainingTime) {
refreshToken(res?.data)
} else {
sessionStorage.setItem('Authorization', res?.data?.value);
sessionStorage.setItem('refreshToken', res?.data?.refreshToken.value);
sessionStorage.setItem('scope', res?.data?.scope);
history.push('/redirect');
}
}
});
}
}
}
2022-03-10 14:24:13 +08:00
const handleOk = () => { // 确定修改密码
if (changeForm.getFieldValue("newPassword") !== changeForm.getFieldValue("newPassword1")) {
message.warn('两次密码输入不一致,请重新输入')
} else {
changeForm.validateFields().then(res => {
setSping(true);
const date = {
identityCard: changeForm.getFieldValue("identityCard"),
oldPassword: changeForm.getFieldValue("oldPassword"),
newPassword: changeForm.getFieldValue("newPassword"),
};
changePass({ ...date }).then(res => {
if (res.success) {
setSping(false);
setIsModalVisible(false)
message.success('修改密码成功');
changeForm.resetFields()
} else {
setSping(false);
}
}).finally(() => {
setSping(false);
});;
})
}
}
2022-08-17 17:21:01 +08:00
//登录模式改变事件
const LoginModeChangeEvent = (mode: any) => {
switch(mode){
case 1:
setIsFaceLogin(true);
InitMedia();
break;
case 2:
setIsFaceLogin(false);
break;
}
}
//浏览器类型
const BrowserType = () =>{
//取得浏览器的userAgent字符串
var userAgent = navigator.userAgent;
//判断是否IE<11
var isIE = userAgent.indexOf("compatible") > -1 && userAgent.indexOf("MSIE") > -1;
//判断是否IE的Edge浏览器
var isEdge = userAgent.indexOf("Edge") > -1 && !isIE;
//判断是否IE11
var isIE11 = userAgent.indexOf("Trident") > -1 && userAgent.indexOf("rv:11.0") > -1;
if(isIE){
var reIE = new RegExp("MSIE(\\d+\\.\\d+);");
reIE.test(userAgent);
var fIEVersion = parseFloat(RegExp["$1"]);
if(fIEVersion == 7){
return 7;
}else if(fIEVersion == 8){
return 8;
}else if(fIEVersion == 9){
return 9;
}else if(fIEVersion == 10){
return 10;
}else{
//IE版本<=7
return 6;
}
}else if(isEdge){
return 'edge';
}else if(isIE11){
//IE11
whetherIE.current = true;
return 11;
}else{
//不是IE浏览器
return -1;
}
}
//初始化video
const InitMedia = () => {
BrowserType();
if(!whetherIE.current){
InitUserMedia({video : {width: 480, height: 320}}, success, error);
}
};
//访问用户媒体设备的兼容方法
const InitUserMedia = (constraints: any, success: any, error: any) => {
if (navigator.mediaDevices.getUserMedia) {
//最新的标准API
navigator.mediaDevices.getUserMedia(constraints).then(success).catch(error);
} else if (navigator.webkitGetUserMedia) {
//webkit核心浏览器
navigator.webkitGetUserMedia(constraints,success, error);
} else if (navigator.mozGetUserMedia) {
//firfox浏览器
navigator.mozGetUserMedia(constraints, success, error);
} else if (navigator.getUserMedia) {
//旧版API
navigator.getUserMedia(constraints, success, error);
}
}
//调用媒体设备成功回调方法
const success = (stream: any) => {
//兼容webkit核心浏览器
const CompatibleURL = window.URL || window.webkitURL;
//将视频流设置为video元素的源
console.log(stream);
//video.src = CompatibleURL.createObjectURL(stream);
video.current.srcObject = stream;
video.current.play();
}
//调用媒体设备失败回调方法
const error = (error:any) => {
message.warn('无法获取到摄像头权限,请确认是否存在摄像头及是否授权使用摄像头');
console.log(`访问用户媒体设备失败${error.name}, ${error.message}`);
}
2022-09-02 16:10:56 +08:00
2022-08-17 17:21:01 +08:00
//base64转blob
const base64ToBlob = (base64:string) =>{
const parts = base64.split(";base64,");
const contentType = parts[0].split(":")[1];
const raw = window.atob(parts[1]);
const rawLength = raw.length;
const uInt8Array = new Uint8Array(rawLength);
for (let i = 0; i < rawLength; i += 1) {
uInt8Array[i] = raw.charCodeAt(i);
2022-08-17 17:21:01 +08:00
}
return new Blob([uInt8Array], { type: contentType });
};
2022-09-02 16:10:56 +08:00
//RgbToBase64
const RgbToBase64 = async (image:any) =>{
await rgbToBase64({image}).then(res => {
const _blob = base64ToBlob( 'data:image/jpg;base64,' + res.data);
hanleFaceSubmit(_blob, null);
2022-09-02 16:10:56 +08:00
});
2022-08-17 17:21:01 +08:00
}
2022-03-10 14:24:13 +08:00
useEffect(() => {
cookie.remove('mall3_token');
sessionStorage.clear();
changeCaptcha();
}, []);
return (
<Spin spinning={spinning}>
<div className="login-box">
<div className="top">
<img src={logo} />
<h3> | </h3>
<Button className="change" danger style={{ borderColor: '#b30000', color: '#b30000' }} onClick={() => (setIsModalVisible(true), changeForm.resetFields())}></Button>
</div>
<div className="main">
<div className="text">
<h3> </h3>
2022-08-17 17:21:01 +08:00
{!isFaceLogin ? (
2022-03-10 14:24:13 +08:00
<Form
name="basic"
className="form-box"
initialValues={{ remember: true }}
form={form}
onFinish={handleSubmit}
// 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="请输入密码"
2022-08-17 17:21:01 +08:00
addonAfter={<VideoCameraOutlined onClick={() => LoginModeChangeEvent(1)}/>}
2022-03-10 14:24:13 +08:00
/>
</Form.Item>
<Row>
<Col span={14}>
<Form.Item
label=""
name="captcha"
rules={[{ required: true, message: '请输入验证码!' }]}
>
<Input
prefix={
<SafetyCertificateOutlined
style={{ fontSize: '18px' }}
className="site-form-item-icon"
/>
}
placeholder="请输入验证码"
/>
</Form.Item>
</Col>
<Col span={10}>
<img className="verification" onClick={() => changeCaptcha()} src={imgUrl} />
</Col>
</Row>
{/* <Form.Item className="remember" name="remember" valuePropName="checked">
<Checkbox></Checkbox>
</Form.Item> */}
<Form.Item>
<Button type="primary" className="w100" htmlType="submit">
</Button>
</Form.Item>
2022-08-17 17:21:01 +08:00
</Form>):(
<Form
name="basic"
className="form-box"
initialValues={{ remember: true }}
form={form}
2022-09-02 16:10:56 +08:00
onFinish={hanleFaceSubmit.bind(this, null)}
2022-08-17 17:21:01 +08:00
// onFinishFailed={onFinishFailed}
>
<Form.Item
label=""
name="userName"
rules={[{ required: true, message: '请输入用户名!' }]}
>
<Input
prefix={
<UserOutlined style={{ fontSize: '18px' }} className="site-form-item-icon" />
}
placeholder="请输入用户名"
addonAfter = {<LockOutlined onClick={() => LoginModeChangeEvent(2)}/>}
/>
</Form.Item>
{/* 加载摄像头 */}
<Form.Item>
{!whetherIE.current ? (<video ref={video} width="382" height="200"></video>):(<FrameFaceLogin faceCompareEvent = {RgbToBase64}/>)}
2022-08-17 17:21:01 +08:00
</Form.Item>
<Form.Item>
2022-09-02 16:10:56 +08:00
{/* onClick={() => {hanleFaceSubmit(null, null);}} */}
<Button type="primary" className="w100" htmlType="submit">
2022-08-17 17:21:01 +08:00
</Button>
</Form.Item>
</Form>)}
2022-03-10 14:24:13 +08:00
</div>
</div>
{/* <div className="footer">版权所有:中国联合网络通信有限公司</div> */}
<Modal
title="修改密码"
visible={isModalVisible}
onCancel={() => setIsModalVisible(false)}
footer={[
<Button onClick={() => handleOk()} loading={spinning}> </Button>,
<Button onClick={() => setIsModalVisible(false)}> </Button>
]}
width={600}
>
<Spin spinning={spinning}>
<Form
{...layout}
name="basic"
form={changeForm}
>
<Form.Item
label="身份证(用户名)"
name="identityCard"
rules={[
{
required: true,
message: '请输入身份证(用户名)',
},
]}
>
<Input />
</Form.Item>
<Form.Item
label="原密码"
name="oldPassword"
rules={[
{
required: true,
message: '请输入原始密码',
},
]}
>
<Input.Password />
</Form.Item>
<Form.Item
label="新密码"
name="newPassword"
rules={[
{
required: true,
validator: (rule, value, callback) => {
const oNumber = new RegExp(/\d/);
const oLetter = new RegExp(/[a-zA-Z]/);
const oSpecial = '.~!@#$%^&*()_+=-{}|:<>?,./[]-;\\"';
if (!value) {
callback('请输入新密码');
return;
}
if (value.length < 6) {
callback('密码不能小于六位至少含字母、数字、特殊字符其中的2种');
return;
}
try {
[...value].forEach(val => {
if (
!(
oNumber.test(val) ||
oLetter.test(val) ||
oSpecial.indexOf(val) >= 0
)
) {
throw new Error();
}
});
} catch (e) {
callback('密码不能小于六位至少含字母、数字、特殊字符其中的2种');
}
const contain: boolean[] = [];
[...value].forEach(val => {
if (oNumber.test(val)) {
contain[0] = true;
}
if (oLetter.test(val)) {
contain[1] = true;
}
if (oSpecial.indexOf(val) >= 0) {
contain[2] = true;
}
});
if (contain.filter(item => item === true).length < 2) {
callback('密码不能小于六位至少含字母、数字、特殊字符其中的2种');
return;
}
callback();
}
}
]}
// rules={[
// {
// required: true,
// message: '请输入新密码',
// },
// ]}
>
<Input.Password />
</Form.Item>
<Form.Item
label="新密码确认"
name="newPassword1"
rules={[
{
required: true,
message: '请再次输入新密码',
},
]}
>
<Input.Password />
</Form.Item>
</Form>
</Spin>
</Modal>
</div>
</Spin>
);
};
export default Index;
2022-08-17 17:21:01 +08:00