Commit 0e5eecd5 authored by 周宏民's avatar 周宏民

fix: 验证码登录

parent 464eb3b2
Pipeline #94688 passed with stages
...@@ -92,7 +92,12 @@ const appReducer = (state = initialState, action) => { ...@@ -92,7 +92,12 @@ const appReducer = (state = initialState, action) => {
window.__INITIAL_STATE__.menu = 'banner-left'; window.__INITIAL_STATE__.menu = 'banner-left';
const temp = AppConfig(window.__INITIAL_STATE__); const temp = AppConfig(window.__INITIAL_STATE__);
temp.displayMode = window.__INITIAL_STATE__?.displayMode || ''; temp.displayMode = window.__INITIAL_STATE__?.displayMode || '';
// 验证码开启 系统配置表里配置
temp.isVerification = action.data.isVerification || ''; temp.isVerification = action.data.isVerification || '';
// 验证码配置 站点设置里配置 只针对该站点
temp.isVerificationCode = action.data.VerificationConfig?.IsVerificationCode || false;
temp.verificationCodeTimeOut = action.data.VerificationConfig?.VerificationCodeTimeOut || 1;
temp.verificationCodeType = action.data.VerificationConfig?.VerificationCodeType || '';
window.globalConfig = temp; window.globalConfig = temp;
// eslint-disable-next-line no-undef // eslint-disable-next-line no-undef
......
...@@ -2,7 +2,7 @@ import 'kit_logger'; ...@@ -2,7 +2,7 @@ import 'kit_logger';
import React, { useCallback, useEffect, useState, useRef } from 'react'; import React, { useCallback, useEffect, useState, useRef } from 'react';
import { FieldNumberOutlined, ReloadOutlined } from '@ant-design/icons'; import { FieldNumberOutlined, ReloadOutlined } from '@ant-design/icons';
import { Button, Form, Input, message } from 'antd'; import { Button, Form, Input, message, Space } from 'antd';
import omit from 'omit.js'; import omit from 'omit.js';
import { useIntl } from '@wisdom-utils/components'; import { useIntl } from '@wisdom-utils/components';
...@@ -38,6 +38,8 @@ const ValidateCode = props => { ...@@ -38,6 +38,8 @@ const ValidateCode = props => {
const codeUrl = window?.globalConfig?.hasGateWay const codeUrl = window?.globalConfig?.hasGateWay
? '/PandaCore/Identity/GetVerificationCode' ? '/PandaCore/Identity/GetVerificationCode'
: '/PandaCore/GCK/BussinessAuth/GetVerificationCode'; : '/PandaCore/GCK/BussinessAuth/GetVerificationCode';
const verificationCodeTimeOut = (window?.globalConfig?.verificationCodeTimeOut || 1) * 60;
const onTimeOver = () => { const onTimeOver = () => {
console.log('超时了'); console.log('超时了');
setIsOver(true); setIsOver(true);
...@@ -75,14 +77,13 @@ const ValidateCode = props => { ...@@ -75,14 +77,13 @@ const ValidateCode = props => {
}, []); }, []);
useEffect(() => { useEffect(() => {
if (!isOver) { if (!isOver) {
console.log('开始计时');
if (timer.current) { if (timer.current) {
clearInterval(timer.current); clearInterval(timer.current);
timer.current = null; timer.current = null;
} }
timer.current = setTimeout(() => { timer.current = setTimeout(() => {
onTimeOver(); onTimeOver();
}, 60 * 1000); }, verificationCodeTimeOut * 1000);
} }
return () => { return () => {
if (timer.current) { if (timer.current) {
...@@ -119,7 +120,8 @@ const ValidateCode = props => { ...@@ -119,7 +120,8 @@ const ValidateCode = props => {
}; };
const LoginItem = props => { const LoginItem = props => {
const [count, setCount] = useState(props.countDown || 0); const { isVerificationCode, verificationCodeType, verificationCodeTimeOut } = window.globalConfig;
const [count, setCount] = useState(props.countDown || (verificationCodeTimeOut || 1) * 60);
const [timing, setTiming] = useState(false); const [timing, setTiming] = useState(false);
const [ext, setExt] = useState(''); const [ext, setExt] = useState('');
const intl = useIntl(); const intl = useIntl();
...@@ -136,7 +138,9 @@ const LoginItem = props => { ...@@ -136,7 +138,9 @@ const LoginItem = props => {
tabUtil, tabUtil,
...restProps ...restProps
} = props; } = props;
if (isVerificationCode && (verificationCodeType && verificationCodeType !== '图片验证码') && customProps?.size) {
customProps.size = '';
}
const onGetCaptcha = useCallback(mobile => { const onGetCaptcha = useCallback(mobile => {
// eslint-disable-next-line no-undef // eslint-disable-next-line no-undef
if (window.globalConfig?.hasGateWay) { if (window.globalConfig?.hasGateWay) {
...@@ -178,21 +182,23 @@ const LoginItem = props => { ...@@ -178,21 +182,23 @@ const LoginItem = props => {
useEffect(() => { useEffect(() => {
let interval = 0; let interval = 0;
const { countDown } = props; const { countDown } = props;
const timeDown = countDown || (verificationCodeTimeOut || 1) * 60;
if (timing) { if (timing) {
interval = window.setInterval(() => { interval = window.setInterval(() => {
setCount(preSecond => { setCount(preSecond => {
if (preSecond <= 1) { if (preSecond <= 1) {
setTiming(false); setTiming(false);
clearInterval(interval); clearInterval(interval);
return countDown || 60; return timeDown;
} }
return preSecond - 1; return preSecond - 1;
}); });
}, 1000); }, 1000);
} }
return () => clearInterval(interval); return () => clearInterval(interval);
}, [props, timing]); }, [props.countDown, timing]);
if (!name) { if (!name) {
return null; return null;
...@@ -256,6 +262,46 @@ const LoginItem = props => { ...@@ -256,6 +262,46 @@ const LoginItem = props => {
} }
if (type === 'Validate') { if (type === 'Validate') {
// 短信验证码
if (verificationCodeType === '阿里云短信验证码') {
const inputProps = omit(otherProps, ['onGetCaptcha', 'countDown']);
return (
<>
<FormItem name="mobile" rules={ItemMap.Mobile.rules}>
<Input {...ItemMap.Mobile.props} size="middle" placeholder="请输入手机号码" />
</FormItem>
<FormItem shouldUpdate style={{ marginBottom: '0px' }}>
{({ getFieldValue, validateFields }) => (
<Space align="start">
<FormItem name={name} {...options} rules={rules}>
<Input {...customProps} {...inputProps} />
</FormItem>
<Button
disabled={timing}
className={styles.getCaptcha}
style={{ lineHeight: '32px', width: '110px', textAlign: 'center' }}
size="large"
onClick={() => {
validateFields(['mobile'])
.then(values => {
onGetCaptcha(values.mobile);
})
.catch(error => {
Logger.log(error);
});
}}
>
{timing
? `${intl.formatMessage({ id: 'pages.login.phoneLogin.sendCationCode' })}(${count})`
: intl.formatMessage({ id: 'pages.login.phoneLogin.getVerificationCode' })}
</Button>
</Space>
)}
</FormItem>
</>
);
}
// 图形验证码
return ( return (
<Form.Item name={name} {...options}> <Form.Item name={name} {...options}>
<ValidateCode {...customProps} {...otherProps} /> <ValidateCode {...customProps} {...otherProps} />
......
...@@ -14,6 +14,7 @@ const Login = props => { ...@@ -14,6 +14,7 @@ const Login = props => {
const intl = useIntl(); const intl = useIntl();
const { className } = props; const { className } = props;
const otherChildren = []; const otherChildren = [];
React.Children.forEach(props.children, child => { React.Children.forEach(props.children, child => {
if (!child) { if (!child) {
return; return;
...@@ -25,7 +26,9 @@ const Login = props => { ...@@ -25,7 +26,9 @@ const Login = props => {
<div className={classNames(className, styles.login)}> <div className={classNames(className, styles.login)}>
{props.welcome === void 0 ? ( {props.welcome === void 0 ? (
<div className={styles.desc}>{intl.formatMessage({ id: 'pages.login.welcome' })}</div> <div className={styles.desc}>{intl.formatMessage({ id: 'pages.login.welcome' })}</div>
) : props.welcome} ) : (
props.welcome
)}
<Form <Form
form={props.from} form={props.from}
onFinish={values => { onFinish={values => {
......
...@@ -113,6 +113,7 @@ ...@@ -113,6 +113,7 @@
width: 100%; width: 100%;
height: 100%; height: 100%;
object-fit: contain; object-fit: contain;
margin: 0;
} }
.validate_invalid { .validate_invalid {
......
...@@ -44,16 +44,11 @@ const useAccount = props => ( ...@@ -44,16 +44,11 @@ const useAccount = props => (
/> />
{props?.isValidate ? <Validate name="validate" /> : null} {props?.isValidate ? <Validate name="validate" /> : null}
<div> <div>
<Checkbox <Checkbox checked={props.autoLogin} onChange={e => props.setAutoLogin(e.target.checked)}>
checked={props.autoLogin}
onChange={e => props.setAutoLogin(e.target.checked)}
>
{useIntl().formatMessage({ id: 'pages.login.rememberMe' })} {useIntl().formatMessage({ id: 'pages.login.rememberMe' })}
</Checkbox> </Checkbox>
</div> </div>
<Submit loading={props.submitting}> <Submit loading={props.submitting}>{useIntl().formatMessage({ id: 'pages.login.submit' })}</Submit>
{useIntl().formatMessage({ id: 'pages.login.submit' })}
</Submit>
</LoginForm> </LoginForm>
); );
......
...@@ -1567,7 +1567,8 @@ class Login { ...@@ -1567,7 +1567,8 @@ class Login {
loginHandlerValidate(user, pwd, userPhone, isRememberPWD, ref, validateCode = '') { loginHandlerValidate(user, pwd, userPhone, isRememberPWD, ref, validateCode = '') {
const self = this; const self = this;
if ((this.globalConfig?.isVerification || 0) * 1 === 1) // isVerification 取自系统配置表,isVerificationCode 取自 站点配置,isVerificationCode为1 会默认把 isVerificationCode改为true
if ((this.globalConfig?.isVerification || 0) * 1 === 1 || this.globalConfig.isVerificationCode)
return self.loginValidate(user, pwd, userPhone, isRememberPWD, SERVICE_APP_LOGIN_MODE.password, validateCode); return self.loginValidate(user, pwd, userPhone, isRememberPWD, SERVICE_APP_LOGIN_MODE.password, validateCode);
if (user && pwd) { if (user && pwd) {
if (self.loginFailed && self.captchaObj) { if (self.loginFailed && self.captchaObj) {
......
...@@ -37,24 +37,20 @@ const Login = forwardRef((props, _ref) => { ...@@ -37,24 +37,20 @@ const Login = forwardRef((props, _ref) => {
const [action, setAction] = useState(() => new LoginAction(Object.assign({}, props, { history }), setVisible, false)); const [action, setAction] = useState(() => new LoginAction(Object.assign({}, props, { history }), setVisible, false));
const [showVideo, setShowVideo] = useState(false); const [showVideo, setShowVideo] = useState(false);
let { ddCode } = props.global; let { ddCode } = props.global;
const { isVerificationCode, isVerification, verificationCodeType } = window.globalConfig;
const isValidate = (isVerification || 0) * 1 === 1 || isVerificationCode;
const loginMode = Cookies.get('loginMode') || null; const loginMode = Cookies.get('loginMode') || null;
if (loginMode && loginMode === 'iotWechat') ddCode = null; if (loginMode && loginMode === 'iotWechat') ddCode = null;
// useEffect(() => {
// action.globalConfig = props.global;
// }, [props.global]);
const handleSubmit = values => { const handleSubmit = values => {
/* eslint-disable */ /* eslint-disable */
action && action &&
(type === 'Account' (type === 'Account'
? action.loginHandler( ? isValidate
values.userName, ? action.loginHandlerValidate(values.userName, values.password, null, autoLogin, 'none', values?.validate)
values.password, : action.loginHandler(values.userName, values.password, null, autoLogin, sliVerify)
null, : type === 'Mobile'
autoLogin,
sliVerify,
)
: type === 'Mobile'
? action.phoneLoginFormHandler(values.mobile, values.captcha) ? action.phoneLoginFormHandler(values.mobile, values.captcha)
: null); : null);
...@@ -64,55 +60,50 @@ const Login = forwardRef((props, _ref) => { ...@@ -64,55 +60,50 @@ const Login = forwardRef((props, _ref) => {
useEffect(() => { useEffect(() => {
// if (props.loginMode === LOGIN_WAY.WeChart) { // if (props.loginMode === LOGIN_WAY.WeChart) {
action && action &&
action.events.on('loginSuccess', event => { action.events.on('loginSuccess', event => {
setSubmitting(false); setSubmitting(false);
props.updateCurrentIndex && props.updateCurrentIndex(0); props.updateCurrentIndex && props.updateCurrentIndex(0);
props.history.push(`/?client=${props.global.client}`); props.history.push(`/?client=${props.global.client}`);
// window.share.event.emit('triggerMicro', props.global); // window.share.event.emit('triggerMicro', props.global);
// initMicroApps(); // initMicroApps();
defaultApp(); defaultApp();
}); });
action && action &&
action.events.on('loginError', event => { action.events.on('loginError', event => {
setVisible(false); setVisible(false);
setSubmitting(false); setSubmitting(false);
}); });
action && action &&
action.events.on('loginVisible', status => { action.events.on('loginVisible', status => {
setVisible(status); setVisible(status);
}); });
action.events.on('loginHomePage', () => { action.events.on('loginHomePage', () => {
props.history.push(`/homePage`); props.history.push(`/homePage`);
}) });
action.events.on('loginIndustry', () => { action.events.on('loginIndustry', () => {
props.history.push(`/industry`); props.history.push(`/industry`);
}); });
return () => { return () => {
action && action.events && action.events.removeAllListeners('loginSuccess'); action && action.events && action.events.removeAllListeners('loginSuccess');
action && action.events && action.events.removeAllListeners('loginError'); action && action.events && action.events.removeAllListeners('loginError');
action && action.events && action.events.removeAllListeners('loginVisible'); action && action.events && action.events.removeAllListeners('loginVisible');
action && action.events && action.events.removeAllListeners('loginHomePage'); action && action.events && action.events.removeAllListeners('loginHomePage');
action && action.events && action.events.removeAllListeners('loginIndustry'); action && action.events && action.events.removeAllListeners('loginIndustry');
} };
}, [props.loginMode]); }, [props.loginMode]);
let loginTimeInterval = null; let loginTimeInterval = null;
let videoTimeout = null; let videoTimeout = null;
useEffect(() => { useEffect(() => {
if (loginTimeInterval) if (loginTimeInterval) clearInterval(loginTimeInterval), (loginTimeInterval = null);
clearInterval(loginTimeInterval), (loginTimeInterval = null);
loginTimeInterval = setInterval(() => { loginTimeInterval = setInterval(() => {
const date = new Date(); const date = new Date();
const weekday = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']; const weekday = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
const time = `${ const time = `${date.getHours() < 10 ? `0${date.getHours()}` : date.getHours()}:${
date.getHours() < 10 ? `0${date.getHours()}` : date.getHours()
}:${
date.getMinutes() < 10 ? `0${date.getMinutes()}` : date.getMinutes() date.getMinutes() < 10 ? `0${date.getMinutes()}` : date.getMinutes()
}:${ }:${date.getSeconds() < 10 ? `0${date.getSeconds()}` : date.getSeconds()}`;
date.getSeconds() < 10 ? `0${date.getSeconds()}` : date.getSeconds()
}`;
setCurrentDate({ setCurrentDate({
time, time,
dayofweek: weekday[date.getDay()], dayofweek: weekday[date.getDay()],
...@@ -125,7 +116,7 @@ const Login = forwardRef((props, _ref) => { ...@@ -125,7 +116,7 @@ const Login = forwardRef((props, _ref) => {
}, []); }, []);
useEffect(() => { useEffect(() => {
if(ddCode && loginMode === 'qywx') { if (ddCode && loginMode === 'qywx') {
setShowVideo(false); setShowVideo(false);
} else { } else {
setShowVideo(true); setShowVideo(true);
...@@ -176,11 +167,11 @@ const Login = forwardRef((props, _ref) => { ...@@ -176,11 +167,11 @@ const Login = forwardRef((props, _ref) => {
switch (template) { switch (template) {
case 'DarkCloud.html': case 'DarkCloud.html':
case 'Dark.html': case 'Dark.html':
return <Account {...params} />; return <Account {...params} isValidate={isValidate} />;
case 'Dark - IOTMultiLogin.html': case 'Dark - IOTMultiLogin.html':
return <IotComponent {...params} />; return <IotComponent {...params} />;
default: default:
return <Account {...params} />; return <Account {...params} isValidate={isValidate} />;
} }
}; };
/* eslint-disable */ /* eslint-disable */
...@@ -192,111 +183,68 @@ const Login = forwardRef((props, _ref) => { ...@@ -192,111 +183,68 @@ const Login = forwardRef((props, _ref) => {
<meta name="description" content={props.global.title || defaultSetting.title} /> <meta name="description" content={props.global.title || defaultSetting.title} />
</Helmet> </Helmet>
<div className={styles.main}> <div className={styles.main}>
{showVideo && <video {showVideo && (
src={require("../../../../assets/videos/beforPage.mp4") } <video
className={styles.videLayer} src={require('../../../../assets/videos/beforPage.mp4')}
autoPlay="autoPlay" className={styles.videLayer}
muted autoPlay="autoPlay"
playsInline="playsinline" muted
ref={videoRef} playsInline="playsinline"
/>} ref={videoRef}
/>
)}
<div className={styles.inner}> <div className={styles.inner}>
<div <div className={classNames(styles.loginTime, styles.caseHide)} ref={loginRef}>
className={classNames(styles.loginTime, styles.caseHide)}
ref={loginRef}
>
<img <img
role="logo" role="logo"
src={props.global && props.global.transformDevAssetsBaseURL && props.global.transformDevAssetsBaseURL(props.global.logo)} src={
props.global &&
props.global.transformDevAssetsBaseURL &&
props.global.transformDevAssetsBaseURL(props.global.logo)
}
/> />
<div <div className={classNames(styles.titleCase, styles.caseHide, 'animated')} ref={titleRef}>
className={classNames(
styles.titleCase,
styles.caseHide,
'animated',
)}
ref={titleRef}
>
<span className={styles.title}>{props.global.title}</span> <span className={styles.title}>{props.global.title}</span>
<span className={styles.subtitle}> <span className={styles.subtitle}>{window.globalConfig && window.globalConfig.subtitle}</span>
{window.globalConfig && window.globalConfig.subtitle}
</span>
</div> </div>
</div> </div>
<span <span className={classNames(styles.divider, styles.caseHide, 'animate__animated')} />
className={classNames( <div className={classNames(styles.timeCase, styles.caseHide, 'animate__animated')} ref={timeRef}>
styles.divider,
styles.caseHide,
'animate__animated',
)}
/>
<div
className={classNames(
styles.timeCase,
styles.caseHide,
'animate__animated',
)}
ref={timeRef}
>
<span className={styles.time}>{currentDate.time}</span> <span className={styles.time}>{currentDate.time}</span>
<span className={styles.dayofweek}>{currentDate.dayofweek}</span> <span className={styles.dayofweek}>{currentDate.dayofweek}</span>
<span className={styles.date}>{currentDate.date}</span> <span className={styles.date}>{currentDate.date}</span>
</div> </div>
<div <div className={classNames(styles['login-block'], styles.caseHide, 'animate__animated')} ref={loginFormRef}>
className={classNames(
styles['login-block'],
styles.caseHide,
'animate__animated',
)}
ref={loginFormRef}
>
<div> <div>
<img src={require('@/assets/images/login/dark/login.png')} /> <img src={require('@/assets/images/login/dark/login.png')} />
</div> </div>
<div className={styles['login-form']}>{renderPlatform()}</div> <div className={styles['login-form']}>{renderPlatform()}</div>
</div> </div>
</div> </div>
<div <div className={classNames(styles.footerCase, styles.caseHide, 'animate__animated')} ref={footerRef}>
className={classNames(
styles.footerCase,
styles.caseHide,
'animate__animated',
)}
ref={footerRef}
>
<div className={classNames(styles.quickMark)}>{renderAddons}</div> <div className={classNames(styles.quickMark)}>{renderAddons}</div>
<span className={classNames(styles.copyright)}> <span className={classNames(styles.copyright)}>
Copyright © Copyright ©
<a target="_blank" href="https://panda-water.cn"> <a target="_blank" href="https://panda-water.cn">
熊猫智慧水务 熊猫智慧水务
</a>
{new Date().getFullYear()} All Rights Reserved{' '}
{
window.location.host.includes("panda-water") ?
<a target="_blank" id="IndexCaseNumber" href="https://beian.miit.gov.cn">
ICP18045097-1
</a> : ""
}
<span className="addons">
<span className="split" />
<a id="qrcode">
<span
className="glyphicon glyphicon-qrcode"
role="button"
title="手持APP下载"
/>
</a> </a>
{new Date().getFullYear()} All Rights Reserved{' '}
{window.location.host.includes('panda-water') ? (
<a target="_blank" id="IndexCaseNumber" href="https://beian.miit.gov.cn">
ICP18045097-1
</a>
) : (
''
)}
<span className="addons">
<span className="split" />
<a id="qrcode">
<span className="glyphicon glyphicon-qrcode" role="button" title="手持APP下载" />
</a>
</span>
</span> </span>
</span>
</div> </div>
<Modal <Modal centered visible={visible} width={340} footer={null} closable={false} bodyStyle={{ padding: '15px' }}>
centered
visible={visible}
width={340}
footer={null}
closable={false}
bodyStyle={{ padding: '15px' }}
>
<div ref={sliVerify} /> <div ref={sliVerify} />
</Modal> </Modal>
</div> </div>
...@@ -326,4 +274,4 @@ const mapDispatchToProps = dispatch => ({ ...@@ -326,4 +274,4 @@ const mapDispatchToProps = dispatch => ({
export default connect( export default connect(
mapStateToProps, mapStateToProps,
mapDispatchToProps, mapDispatchToProps,
)((Login)); )(Login);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment