Commit 43b865de authored by 周宏民's avatar 周宏民

feat: 云平台登录页

parent 4c0bcfbc
Pipeline #89847 waiting for manual action with stages
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
......@@ -122,7 +122,11 @@ const Demonstration = props => {
jumpProgressStart();
setLinkUrl(url);
startTiming(15);
let time = 15;
if (!url.includes('user/noscret')) {
time = 4;
}
startTiming(time);
};
const handError = err => {
......@@ -468,7 +472,7 @@ const Demonstration = props => {
useEffect(() => {}, []);
return (
<div className={classNames(styles.demonstration)} ref={ref}>
{!linkUrl ? (
{/* {!linkUrl ? (
<div
className={classNames(styles.iframeExit, 'animate__animated', 'animate__fadeIn')}
onClick={() => props.logout && props.logout()}
......@@ -481,7 +485,7 @@ const Demonstration = props => {
退出
</div>
</div>
) : null}
) : null} */}
{jumpLoading ? (
<div className={styles.demonstrationLoad} key="jumpLoading">
<div style={{ width: '285px' }}>
......
/*
* @Author: 634665781 634665781@qq.com
* @Date: 2022-07-08 14:28:01
* @LastEditors: 634665781 634665781@qq.com
* @LastEditTime: 2024-04-26 10:13:08
* @LastEditors: Please set LastEditors
* @LastEditTime: 2024-06-14 19:47:04
* @FilePath: \CivWeb\src\pages\user\login\index.js
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
......@@ -21,6 +21,7 @@ import EnergGzV2 from './template/energy_GZV2/index'; // 广州单点登录跳
import EnergJS2 from './template/energy_JS2/index';
import DarkNoEffect from './template/noEffect/DarkNoEffect';
import CloudLogin from './template/cloud';
import CloudNewLogin from './template/cloudNew';
import WaterLogin from './template/water';
import JSZHLogin from './template/project/JSZH';
import ChengmaiLogin from './template/project/chengmai';
......@@ -58,6 +59,7 @@ const LoginTemplate = {
'Dark.html': BaseLogin,
'DarkCloud.html':
window.location.origin.replace(/^(http|https):\/\//, '') === 'panda-water.cn' ? CloudLogin : BaseLogin,
'云平台.html': CloudNewLogin,
'信息化.html': InfoLogin,
'项目 - 榆林.html': Yulin,
'能源-定额平台.html': EnergyQuota,
......@@ -99,25 +101,28 @@ const LoginTemplate = {
default: BaseLogin,
};
/* eslint-disable */
export default (props) => {
export default props => {
const { location } = props.history;
useEffect(() => {
if (location.state && location.state.reload && !window.qiankunIsCache) {
AppInitState();
}
}, []);
if (Object.keys(window.globalConfig || {}).length === 0 || (window.globalConfig && !window.globalConfig.loginTemplate)) return null;
if (
Object.keys(window.globalConfig || {}).length === 0 ||
(window.globalConfig && !window.globalConfig.loginTemplate)
)
return null;
let template = window.globalConfig && window.globalConfig.loginTemplate;
let arr = template.split('|')
let loginParams = []
let arr = template.split('|');
let loginParams = [];
if (arr.length > 1) {
template = arr[0]
loginParams = arr[1].split('&')
template = arr[0];
loginParams = arr[1].split('&');
}
if (template.indexOf('.html') == -1) {
template += '.html';
}
const RenderComponent = LoginTemplate[template] ? LoginTemplate[template] : LoginTemplate['default'];
return <RenderComponent {...props} loginParams={loginParams} />
return <RenderComponent {...props} loginParams={loginParams} />;
};
/*
* @Title:
* @Author: hongmye
* @Date: 2024-06-14 14:55:21
*/
import { Checkbox } from 'antd';
import React from 'react';
import { useIntl } from '@wisdom-utils/components';
import LoginMessage from '@/pages/user/login/js/loginMessage';
import LoginForm from '@/pages/user/login/components/Login';
import userIcon from '@/assets/images/login/cloud/user.png';
import passwordIcon from '@/assets/images/login/cloud/password.png';
import styles from './index.less';
/* eslint-disable */
const { UserName, Password, Submit } = LoginForm;
const useAccount = props => (
<LoginForm onSubmit={props.onSubmit} welcome={props.welcome} className={styles.cloudLoginFrom}>
{props.status === 'error' && props.type === 'account' && !props.submitting && (
<LoginMessage
content={useIntl().formatMessage({
id: 'pages.login.accountLogin.errorMessage',
})}
/>
)}
<UserName
name="userName"
prefix={<img src={userIcon} className={styles.prefixIcon} alt="" />}
placeholder={useIntl().formatMessage({
id: 'pages.login.username.placeholder',
})}
rules={[
{
required: true,
message: useIntl().formatMessage({
id: 'pages.login.username.required',
}),
},
]}
/>
<Password
name="password"
prefix={<img src={passwordIcon} className={styles.prefixIcon} alt="" />}
placeholder={useIntl().formatMessage({
id: 'pages.login.password.placeholder',
})}
rules={[
{
required: true,
message: useIntl().formatMessage({
id: 'pages.login.password.required',
}),
},
]}
/>
<Submit
style={{ borderRadius: '20px', background: 'linear-gradient(0deg, #067DE3 0%, #2C8FF7 100%)' }}
loading={props.submitting}
>
{useIntl().formatMessage({ id: 'pages.login.submit' })}
</Submit>
</LoginForm>
);
export default useAccount;
/*
* @Title:
* @Author: hongmye
* @Date: 2024-06-14 11:24:47
*/
import React, { useEffect, useState } from 'react';
import { encode } from 'js-base64';
import Cookies from 'js-cookie';
import { LOGIN_WAY, WECOM_APPID, AGENTID_CLOUD } from '@/constants';
import styles from './index.less';
const useWeCom = props => {
useEffect(() => {
window.WwLogin({
id: props.container || 'wxlogin_container',
appid: props.appid || WECOM_APPID,
agentid: props.agentid || AGENTID_CLOUD,
redirect_uri: props.redirect_uri || encodeURIComponent(window.location.href),
// redirect_uri: 'https://panda-water.cn/',
href: props.href || 'https://panda-water.cn/web4/styles/wxNew.css',
self_redirect: false,
state: props.state || 'STATE',
});
}, []);
};
const useIOTQRCode = () => {
const [rstate, setRstate] = useState(() =>
encode(`panda_${Math.round(Math.random() * 10000 + Date.now()).toString(16)}`),
);
useEffect(() => {
Cookies.set('redirect_state', rstate, {
expires: 5 * 60 * 1000,
path: '/',
});
}, []);
const redirectURI = function() {
let redirectUri = window.location.href;
if (redirectUri.indexOf('loginWay') > -1) return redirectUri;
if (redirectUri.indexOf('?') > -1) redirectUri += `&loginWay=${LOGIN_WAY.WeCom}`;
else redirectUri += `?loginWay=${LOGIN_WAY.WeCom}`;
return redirectUri;
};
const props = Object.assign(
{},
{
container: 'wxlogin_container',
appid: WECOM_APPID,
agentid: AGENTID_CLOUD,
redirect_uri: encodeURIComponent(window.location.href), // window.location.href
href: 'https://panda-water.cn/web4/styles/wxNew.css',
state: rstate,
},
);
useWeCom(props);
return (
<div className={styles.wxlogin_container_wrap}>
<div id="wxlogin_container" className={styles.wxlogin_container} />
</div>
);
};
export default useIOTQRCode;
import Cookies from 'js-cookie';
import React from 'react';
import { LOGIN_DISPLAY, LOGIN_WAY } from '@/constants';
import Account from './Account';
import WeComLogin from './WeComLogin';
import styles from './index.less';
const useIOTComponent = props => {
const handlerType = type => {
props.setType(type);
props.updateLoginMode(LOGIN_WAY[type]);
Cookies.set('loginMode', LOGIN_WAY[type], {
expires: 5 * 60 * 1000,
path: '/',
});
};
return (
<div className={styles.wechatQRcode}>
{props.type === LOGIN_DISPLAY.Account ? (
<Account {...props} />
) : props.type === LOGIN_DISPLAY.WeCom ? (
<WeComLogin {...props} />
) : (
<Account {...props} />
)}
</div>
);
};
export default useIOTComponent;
import '@wisdom-utils/utils/lib/helpers/format';
import React, { forwardRef, useEffect, useRef, useState } from 'react';
import { connect } from 'react-redux';
import { Modal, Tabs } from 'antd';
import { Helmet, HelmetProvider } from 'react-helmet-async';
import classNames from 'classnames';
import { dom } from '@wisdom-utils/utils/lib/helpers';
import { useHistory, withRouter } from '@wisdom-utils/runtime';
import Cookies from 'js-cookie';
import { actionCreators } from '@/containers/App/store';
import { LOGIN_WAY, LOGIN_DISPLAY } from '@/constants';
import defaultSetting from '../../../../../../config/defaultSetting';
import LoginAction from '../../login';
import styles from './index.less';
import useRenderQcode from '../../js/useRenderQcode';
import CloudForm from './cloudForm';
import { defaultApp } from '../../../../../micro';
import useTime from '../../js/useTime';
const isRQcodeFunc = loginFunc => {
const rqcodeFuncs = [LOGIN_DISPLAY.WeChart, LOGIN_DISPLAY.WeCom];
return !!(loginFunc && rqcodeFuncs.indexOf(loginFunc) !== -1);
};
const Login = forwardRef((props, _ref) => {
let originType = window.location.origin.replace(/^(http|https):\/\//, '') === 'panda-water.cn';
originType = true;
const loginRef = useRef();
const timeRef = useRef();
const titleRef = useRef();
const sliVerify = useRef();
const loginFormRef = useRef();
const formRef = useRef(null);
const footerRef = useRef();
const currentDate = useTime(); // 计时时间
const [status, setStatus] = useState('normal');
const [autoLogin, setAutoLogin] = useState(false); // 是否记住密码
const [submitting, setSubmitting] = useState(false); // 提交状态
const [type, setType] = useState(originType ? LOGIN_DISPLAY.WeCom : LOGIN_DISPLAY.Account); // 登录方式,type是LOGIN_DISPLAY的value,也是LOGIN_WAY的key,根据type决定loginModel
const [visible, setVisible] = useState(false);
const history = useHistory();
const [action, setAction] = useState(() => new LoginAction(Object.assign({}, props, { history }), setVisible, true));
let { ddCode } = props.global;
const loginMode = Cookies.get('loginMode') || null;
if (loginMode && loginMode === 'iotWechat') ddCode = null;
const handleSubmit = values => {
/* eslint-disable */
action &&
(type === 'Account'
? action.loginHandler(values.userName, values.password, null, autoLogin, sliVerify)
: type === 'Mobile'
? action.phoneLoginFormHandler(values.mobile, values.captcha)
: null);
setSubmitting(true);
props.updateCurrentIndex && props.updateCurrentIndex(-1);
};
useEffect(() => {
action &&
action.events.on('loginSuccess', event => {
setSubmitting(false);
props.updateCurrentIndex && props.updateCurrentIndex(0);
props.history.push(`/?client=${props.global.client}`);
defaultApp();
});
action &&
action.events.on('loginError', event => {
setVisible(false);
setSubmitting(false);
});
action &&
action.events.on('loginVisible', status => {
setVisible(status);
});
// }
return () => {
action && action.events && action.events.removeAllListeners('loginSuccess');
action && action.events && action.events.removeAllListeners('loginError');
action && action.events && action.events.removeAllListeners('loginVisible');
};
}, [props.loginMode]);
useEffect(() => {
if (ddCode && loginMode === 'qywx') {
} else {
dom.removeClass(timeRef.current, styles.caseHide);
dom.addClass(timeRef.current, 'animate__fadeIn');
dom.removeClass(loginFormRef.current, styles.caseHide);
dom.addClass(loginFormRef.current, 'animate__fadeInUp');
dom.removeClass(footerRef.current, styles.caseHide);
dom.addClass(footerRef.current, 'animate__slideInUp');
dom.removeClass(titleRef.current, styles.caseHide);
dom.addClass(titleRef.current, 'animte__fadeInUp');
}
return () => {};
}, []);
useEffect(() => {
setSubmitting(false);
}, [visible]);
const renderAddons = useRenderQcode({ ...props.global, styles });
const renderPlatform = () => {
const template = props.global.loginTemplate;
const params = {
fromRef: formRef,
type,
setType,
status,
submitting,
autoLogin,
setAutoLogin,
action,
onSubmit: handleSubmit,
loginMode: props.loginMode,
updateLoginMode: props.updateLoginMode,
welcome: '',
};
return <CloudForm {...params} />;
};
/* eslint-disable */
const toggleLoginFunc = e => {
e && e.stopPropagation && e.stopPropagation();
setType(isRQcodeFunc(type) ? LOGIN_DISPLAY.Account : LOGIN_DISPLAY.WeCom);
props.updateLoginMode(isRQcodeFunc(type) ? LOGIN_WAY[LOGIN_DISPLAY.Account] : LOGIN_WAY[LOGIN_DISPLAY.WeCom]);
Cookies.set('loginMode', isRQcodeFunc(type) ? LOGIN_WAY[LOGIN_DISPLAY.Account] : LOGIN_WAY[LOGIN_DISPLAY.WeCom], {
expires: 5 * 60 * 1000,
path: '/',
});
};
return (
<HelmetProvider>
<Helmet>
<title>{props.global.title || defaultSetting.title}</title>
<meta name="description" content={props.global.title || defaultSetting.title} />
</Helmet>
<div className={classNames(styles.main, 'cloudLoginWrap')}>
{/* main content */}
<div className={styles.inner}>
<div className={classNames(styles.loginTime, styles.caseHide)} ref={loginRef}>
<img
role="logo"
src={
props.global &&
props.global.transformDevAssetsBaseURL &&
props.global.transformDevAssetsBaseURL(props.global.logo)
}
/>
<div className={classNames(styles.titleCase, styles.caseHide, 'animated')} ref={titleRef}>
<span className={styles.title}>{props.global.title}</span>
<span className={styles.subtitle}>{window.globalConfig.subtitle}</span>
</div>
</div>
<div className={classNames(styles.timeCase, styles.caseHide, 'animate__animated')} ref={timeRef}>
<span className={styles.time}>{currentDate.time}</span>
<span className={styles.dayofweek}>{currentDate.dayofweek}</span>
<span className={styles.date}>{currentDate.date}</span>
</div>
{/* login container */}
<div className={classNames(styles['login-block'], styles.caseHide, 'animate__animated')} ref={loginFormRef}>
<div className={styles.login_tab}>
<Tabs
centered={true}
activeKey={type}
tabBarGutter={100}
tabBarStyle={{ color: '#fff', fontSize: '18px' }}
onChange={toggleLoginFunc}
>
<Tabs.TabPane tab="扫码登录" key={LOGIN_DISPLAY.WeCom} disabled={!originType} />
<Tabs.TabPane tab="账号密码登录" key={LOGIN_DISPLAY.Account} />
</Tabs>
</div>
{/* right form */}
<div className={styles['login-form']}>
{/* 登录类型切换,扫码/账号密码 */}
{renderPlatform()}
</div>
</div>
</div>
{/* footer */}
<div className={classNames(styles.footerCase, styles.caseHide, 'animate__animated')} ref={footerRef}>
<div className={classNames(styles.quickMark)}>{renderAddons}</div>
<span className={classNames(styles.copyright)}>
Copyright ©
<a target="_blank" href="https://panda-water.cn">
熊猫智慧水务
</a>
{new Date().getFullYear()} All Rights Reserved{' '}
<a target="_blank" id="IndexCaseNumber" href="">
ICP11036640-1
</a>
<span className="addons">
<span className="split" />
<a id="qrcode">
<span className="glyphicon glyphicon-qrcode" role="button" title="手持APP下载" />
</a>
</span>
</span>
</div>
<Modal centered visible={visible} width={340} footer={null} closable={false} bodyStyle={{ padding: '15px' }}>
<div ref={sliVerify} />
</Modal>
</div>
</HelmetProvider>
);
});
const mapStateToProps = state => ({
global: state.getIn(['global', 'globalConfig']),
loginMode: state.getIn(['global', 'loginMode']),
});
const mapDispatchToProps = dispatch => ({
updateConfig(config) {
dispatch(actionCreators.getConfig(config));
},
createContext(data) {
dispatch(actionCreators.createContext(data));
},
updateLoginMode(mode) {
dispatch(actionCreators.changeLoginMode(mode));
},
updateCurrentIndex(index) {
dispatch(actionCreators.updateCurrentIndex(index));
},
});
export default connect(
mapStateToProps,
mapDispatchToProps,
)(withRouter(Login));
@import '~antd/es/style/themes/default.less';
.main {
height: 100%;
width: 100%;
background: url('@/assets/images/login/cloud/bg.png') no-repeat center center;
background-size: 100% 100%;
}
.inner {
width: 100%;
height: 84%;
@keyframes loginTimeShow {
0% {
opacity: 1;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
zoom: 2;
}
50% {
opacity: 1;
top: 28px;
left: 45px;
transform: translate(0, 0);
zoom: 1;
}
60% {
opacity: 1;
left: 45px;
top: 28px;
transform: translate(0, 0);
}
70% {
opacity: 1;
left: 45px;
top: 28px;
transform: translate(0, 0);
}
75% {
opacity: 1;
left: 45px;
top: 28px;
transform: translate(0, 0);
}
100% {
opacity: 1;
left: 45px;
top: 28px;
transform: translate(0, 0);
}
}
// logo及标题
.loginTime {
position: absolute;
top: 50%;
left: 50%;
display: flex;
align-items: center;
justify-content: center;
opacity: 1;
transform: translate(-50%, -50%);
&.newYearLoginTime {
position: absolute !important;
top: 28px !important;
left: 45px !important;
display: flex;
align-items: center;
justify-content: center;
z-index: 100;
transform: inherit !important;
}
img[role='logo'] {
height: 40px;
vertical-align: middle;
}
&.loginTimeShow {
animation-name: loginTimeShow;
animation-duration: 1s;
animation-iteration-count: 1;
animation-fill-mode: forwards;
}
.titleCase {
display: flex;
flex-direction: column;
margin: -5px 0 0 20px;
max-width: 570px;
.title,
.subtitle {
font-family: 'Microsoft YaHei';
text-align: left;
overflow-wrap: break-word;
color: #ffffff;
}
.title {
font-size: 28px;
}
.subtitle {
font-size: 12px;
line-height: 1;
}
}
}
// 时间
.timeCase {
.time,
.dayofweek,
.date {
position: absolute;
font-family: 'MicrosoftYaHeiUI';
color: rgba(255, 255, 255, 1);
}
.time {
top: 26px;
right: 180px;
font-size: 40px;
}
.dayofweek {
top: 32px;
right: 125px;
font-size: 16px;
}
.date {
top: 57px;
right: 95px;
font-size: 14px;
}
}
// 登录方式
.loginFunc {
position: absolute;
top: 0;
right: 0;
width: 58px;
overflow: hidden;
cursor: pointer;
img {
width: 100%;
margin: 0 !important;
}
}
.loginBlockWrapper {
width: 100%;
height: 100%;
background: url(https://panda-water.com/web4/assets/images/login/workflow/智联新春背景.png);
background-size: 100% 100%;
background-repeat: no-repeat;
}
.login-block {
width: 393px;
height: 469px;
position: absolute;
right: 170px;
top: 50%;
margin-top: -235px;
background: url('@/assets/images/login/cloud/login_bg.png') no-repeat center center;
background-size: 100% 100%;
padding: 135px 30px 50px;
color: #fff;
.login-form {
padding-top: 10px;
}
.loginDisplay {
.loginTab {
color: @primary-6;
}
}
.wxlogin_container_wrap {
width: 188px;
height: 188px;
background: url('@/assets/images/login/cloud/qrCode.png') no-repeat center center;
background-size: 100% 100%;
padding: 11px;
margin: 0 auto;
}
.wxlogin_container {
background: #fff;
width: 100%;
height: 100%;
}
}
.wechatQRcode {
height: 300px;
}
}
.caseHide {
display: none !important;
}
.footerCase {
width: 100%;
height: 16%;
color: #fff;
font-weight: 400;
font-size: 16px;
.quickMark {
position: absolute;
bottom: 48px;
text-align: center;
width: 100%;
font-size: 12px;
min-height: 71px;
&-single {
text-align: center;
width: 120px;
display: inline-block;
span {
&.Android {
display: block;
background-image: url(https://panda-water.cn/web4/assets/images/login/dark/Android1.png);
width: 26px;
height: 32px;
margin: auto;
margin-bottom: 6px;
}
&.Wechat {
display: block;
background-image: url(https://panda-water.cn/web4/assets/images/login/dark/Wechat1.png);
width: 34px;
height: 32px;
margin: auto;
margin-bottom: 6px;
}
&.iphone {
display: block;
background-image: url(https://panda-water.cn/web4/assets/images/login/dark/iphone1.png);
width: 28px;
height: 32px;
margin: auto;
margin-bottom: 6px;
}
}
}
.Android-single .Android-code,
.iphone-single .iphone-code {
margin: 0px 0px 10px 0px;
width: 150px;
height: 150px;
background: #fff;
padding: 5px;
display: none;
transform: translateX(-15px);
}
.icon-Container {
height: 50px;
cursor: pointer;
}
}
.copyright {
position: absolute;
z-index: 2;
text-align: center;
width: 100%;
bottom: 10px;
font-size: 16px;
color: #ffff;
.frontIcon {
margin-top: -5px;
}
a {
color: #fff;
}
.addons {
display: none;
}
.split {
border-left: 1px solid #fff;
margin: 0 8px;
}
.glyphicon-qrcode {
vertical-align: text-top;
}
}
}
.prefixIcon {
width: 20px;
height: 23px;
margin: 0 5px;
}
.cloudLoginFrom {
width: 100% !important;
}
:global {
.cloudLoginWrap {
iframe {
width: 166px !important;
height: 166px !important;
}
.@{ant-prefix}-input-affix-wrapper {
background-color: #071229 !important;
color: #fff;
border: 1px solid #2CB5E3;
}
.@{ant-prefix}-input-affix-wrapper>input.@{ant-prefix}-input {
background: #071229 !important;
color: #fff !important;
}
.@{ant-prefix}-input-affix-wrapper:not(.@{ant-prefix}-input-affix-wrapper-disabled):hover {
border: 1px solid #2CB5E3;
}
.@{ant-prefix}-input-affix-wrapper:focus,
.@{ant-prefix}-input-affix-wrapper-focused {
border: 1px solid #2CB5E3;
}
input:-webkit-autofill {
box-shadow: 0 0 0px 1000px #071229 inset !important;
color: #fff;
}
input::-webkit-input-placeholder {
color: #fff;
}
input:-internal-autofill-previewed,
input:-internal-autofill-selected {
color: #fff;
transition: background-color 5000s ease-in-out 0s !important;
-webkit-box-shadow: 0 0 0px 1000px #071229 inset !important;
}
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
input:-webkit-autofill:active {
color: #fff;
-webkit-text-fill-color: #fff !important; //字体颜色
-webkit-box-shadow: 0 0 0px 1000px #071229 inset !important;
caret-color: #fff;
}
.@{ant-prefix}-input-affix-wrapper input.@{ant-prefix}-input:focus {
box-shadow: none !important;
}
.@{ant-prefix}-tabs-ink-bar {
width: 30px;
}
.@{ant-prefix}-tabs-tab-disabled {
color: rgba(255, 255, 255, 0.8) !important;
}
}
}
\ No newline at end of file
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