Merge remote-tracking branch 'origin/master'

pull/59/head
shao1121353141 2023-09-26 22:17:38 +08:00
commit 2a0407994d
10 changed files with 257 additions and 273 deletions

View File

@ -13,7 +13,7 @@
--------------------------
<div align="center">⭐️ 如果你喜欢 TopIAM请给它一个 Star您的支持将是我们前行的动力。</div>
<div align="center">⭐️ 如果你喜欢 TOPIAM请给它一个 Star您的支持将是我们前行的动力。</div>
--------------------------

View File

@ -68,7 +68,7 @@ export async function getInitialState(): Promise<{
/**
*
*/
console.log('%c欢迎使用 TopIAM 企业数字身份管控平台', 'font-size: 24px;');
console.log('%c欢迎使用 TOPIAM 企业数字身份管控平台', 'font-size: 24px;');
return {
fetchUserInfo,
currentUser: isLoginPath() ? undefined : await fetchUserInfo(),

View File

@ -22,7 +22,7 @@ import Marquee from 'react-fast-marquee';
const message = () => {
return (
<>
<span> TopIAM Star </span>
<span> TOPIAM Star </span>
<a target="_blank" rel="noopener noreferrer" href="https://github.com/topiam/eiam">
GitHub
</a>

View File

@ -121,7 +121,7 @@ const Welcome: React.FC = () => {
color: '#1A1A1A',
}}
>
使 TopIAM
使 TOPIAM
</div>
<p
style={{

View File

@ -22,7 +22,7 @@ import Marquee from 'react-fast-marquee';
const message = () => {
return (
<>
<span> TopIAM Star </span>
<span> TOPIAM Star </span>
<a target="_blank" rel="noopener noreferrer" href="https://github.com/topiam/eiam">
GitHub
</a>

View File

@ -24,7 +24,7 @@ const currentYear = new Date().getFullYear();
export default (props: FooterProps) => (
<DefaultFooter
style={{ backgroundColor: 'transparent' }}
copyright={`2020-${currentYear} TopIAM 版权所有`}
copyright={`2022-${currentYear} TOPIAM 版权所有`}
links={[
{
key: 'website',

View File

@ -20,9 +20,9 @@ import { ICON_LIST } from '@/components/IconFont/constant';
import { IDP_TYPE, RESULT_STATE, SESSION_STATUS } from '@/constants';
import { getCurrentStatus, getLoginEncryptSecret } from '@/services';
import { aesEcbEncrypt } from '@/utils/aes';
import { ProCard, ProForm, ProFormCheckbox, ProFormInstance } from '@ant-design/pro-components';
import { ProForm, ProFormCheckbox, ProFormInstance } from '@ant-design/pro-components';
import { useAsyncEffect, useRequest, useSafeState } from 'ahooks';
import { Alert, App, Avatar, Skeleton, Space, Spin, Tabs, Tooltip } from 'antd';
import { Alert, App, Avatar, Space, Spin, Tabs, Tooltip } from 'antd';
import { nanoid } from 'nanoid';
import { useRef, useState } from 'react';
import { FormattedMessage, Helmet, history, useIntl } from '@umijs/max';
@ -36,12 +36,11 @@ import { accountLogin, getLoginConfig, otpLogin } from './service';
import useStyle from './style';
import { goto } from './utils';
import queryString from 'query-string';
import Banner from '@/components/Banner';
import { omit } from 'lodash';
import { emailValidator } from '@/utils/utils';
import PageLoading from '@/components/PageLoading';
const prefixCls = 'topiam-login';
const showBanner = process.env.PREVIEW_ENV || process.env.NODE_ENV === 'development';
/**
*
@ -313,284 +312,273 @@ const Login = () => {
<Helmet>
<link rel="icon" href={'/favicon.ico'} />
</Helmet>
{showBanner && (
<div className={`${prefixCls}-banner`}>
<Banner />
</div>
)}
<div className={`${prefixCls}-container`}>
<div className={`${prefixCls}-content`}>
<div className={`${prefixCls}-card`}>
{statusLoading ? (
<ProCard>
<Skeleton loading={statusLoading} paragraph={{ rows: 5 }}></Skeleton>
</ProCard>
) : (
<>
{/*登录*/}
{!status && !forgetPassword && (
<>
<div className={`${prefixCls}-top`}>
<img alt="logo" className={`${prefixCls}-logo`} src={'/full-logo.svg'} />
<div className={`${prefixCls}-desc`}>
{intl.formatMessage({ id: 'pages.layout.title' })}
</div>
{statusLoading || loginConfigLoading ? (
<PageLoading />
) : (
<div className={`${prefixCls}-container`}>
<div className={`${prefixCls}-content`}>
<div className={`${prefixCls}-card`}>
{/*登录*/}
{!status && !forgetPassword && (
<>
<div className={`${prefixCls}-top`}>
<img alt="logo" className={`${prefixCls}-logo`} src={'/full-logo.svg'} />
<div className={`${prefixCls}-desc`}>
{intl.formatMessage({ id: 'pages.layout.title' })}
</div>
<div className={`${prefixCls}-main`}>
{/*登录错误*/}
{userLoginState?.status !== RESULT_STATE.SUCCESS &&
currentProvider?.type === IDP_TYPE.ACCOUNT &&
userLoginState?.message && (
<LoginMessage content={userLoginState?.message} />
)}
{/*其他登录方式*/}
{loginConfig?.idps?.map((value) => {
if (
value.type === currentProvider?.type &&
value.code === currentProvider?.code
) {
if (value.type === IDP_TYPE.DINGTALK_OAUTH) {
dingTalkOauthOnClick(value.code);
return <></>;
}
//QQ
if (value.type === IDP_TYPE.QQ_OAUTH) {
qqOauthOnClick(value.code);
return <></>;
}
/* 扫码登录 */
return (
<QrCodeLogin
key={nanoid()}
code={value.code}
name={value.name}
type={currentProvider?.type}
/>
);
</div>
<div className={`${prefixCls}-main`}>
{/*登录错误*/}
{userLoginState?.status !== RESULT_STATE.SUCCESS &&
currentProvider?.type === IDP_TYPE.ACCOUNT &&
userLoginState?.message && <LoginMessage content={userLoginState?.message} />}
{/*其他登录方式*/}
{loginConfig?.idps?.map((value) => {
if (
value.type === currentProvider?.type &&
value.code === currentProvider?.code
) {
if (value.type === IDP_TYPE.DINGTALK_OAUTH) {
dingTalkOauthOnClick(value.code);
return <></>;
}
return <div key={value.code} />;
})}
{
// 用户名密码和短信登录
(currentProvider?.type === IDP_TYPE.ACCOUNT ||
currentProvider?.type === IDP_TYPE.CAPTCHA) && (
<ProForm
initialValues={{ 'remember-me': false }}
autoComplete="off"
formRef={formRef}
submitter={{
searchConfig: {
submitText: intl.formatMessage({
id: 'pages.login.submit',
}),
},
render: (_, dom) => dom.pop(),
submitButtonProps: {
loading,
size: 'large',
htmlType: 'submit',
style: {
width: '100%',
},
//QQ
if (value.type === IDP_TYPE.QQ_OAUTH) {
qqOauthOnClick(value.code);
return <></>;
}
/* 扫码登录 */
return (
<QrCodeLogin
key={nanoid()}
code={value.code}
name={value.name}
type={currentProvider?.type}
/>
);
}
return <div key={value.code} />;
})}
{
// 用户名密码和短信登录
(currentProvider?.type === IDP_TYPE.ACCOUNT ||
currentProvider?.type === IDP_TYPE.CAPTCHA) && (
<ProForm
initialValues={{ 'remember-me': false }}
autoComplete="off"
formRef={formRef}
submitter={{
searchConfig: {
submitText: intl.formatMessage({
id: 'pages.login.submit',
}),
},
render: (_, dom) => dom.pop(),
submitButtonProps: {
loading,
size: 'large',
htmlType: 'submit',
style: {
width: '100%',
},
},
}}
onFinish={async (values) => {
run(values);
return data;
}}
>
<Tabs
activeKey={currentProvider?.type}
destroyInactiveTabPane
onChange={(key) => {
setCurrentProvider({ type: key });
}}
onFinish={async (values) => {
await run(values);
return data;
items={[
{
label: intl.formatMessage({
id: 'pages.login.account-login.tab',
}),
key: IDP_TYPE.ACCOUNT,
children: (
<>
<UsernamePassword />
</>
),
},
{
label: intl.formatMessage({
id: 'pages.login.phone-login.tab',
}),
key: IDP_TYPE.CAPTCHA,
children: (
<>
<Captcha onGetCaptcha={async () => {}} onRef={captchaRef} />
</>
),
},
]}
/>
<div
style={{
marginBottom: 24,
}}
>
<Tabs
activeKey={currentProvider?.type}
destroyInactiveTabPane
onChange={(key) => {
setCurrentProvider({ type: key });
}}
items={[
{
label: intl.formatMessage({
id: 'pages.login.account-login.tab',
}),
key: IDP_TYPE.ACCOUNT,
children: (
<>
<UsernamePassword />
</>
),
},
{
label: intl.formatMessage({
id: 'pages.login.phone-login.tab',
}),
key: IDP_TYPE.CAPTCHA,
children: (
<>
<Captcha onGetCaptcha={async () => {}} onRef={captchaRef} />
</>
),
},
]}
/>
<div
<ProFormCheckbox noStyle name="remember-me">
<FormattedMessage id="pages.login.remember-me" />
</ProFormCheckbox>
<a
style={{
marginBottom: 24,
float: 'right',
}}
onClick={async () => {
setStatusLoading(true);
setForgetPassword(true);
setTimeout(() => {
setStatusLoading(false);
}, 85);
}}
>
<ProFormCheckbox noStyle name="remember-me">
<FormattedMessage id="pages.login.remember-me" />
</ProFormCheckbox>
<a
style={{
float: 'right',
}}
onClick={async () => {
setStatusLoading(true);
setForgetPassword(true);
setTimeout(() => {
setStatusLoading(false);
}, 85);
}}
>
<FormattedMessage id="pages.login.forgot-password" />
</a>
</div>
</ProForm>
)
}
<>
<Spin spinning={loginConfigLoading}>
{!loginConfigLoading && (
<>
{typeof loginConfig?.idps !== 'undefined' &&
loginConfig?.idps?.length > 0 && (
<div className={`${prefixCls}-other`}>
<FormattedMessage id="pages.login.login-with" />
</div>
)}
<Space className={`${prefixCls}-other-content`} align={'center'}>
{
// 不是短信和用户名密码时
currentProvider?.type !== IDP_TYPE.CAPTCHA &&
currentProvider?.type !== IDP_TYPE.ACCOUNT && (
<Tooltip
key={'password'}
title={intl.formatMessage({
id: 'pages.login.account-login.tab',
})}
placement="top"
<FormattedMessage id="pages.login.forgot-password" />
</a>
</div>
</ProForm>
)
}
<>
<Spin spinning={loginConfigLoading}>
{!loginConfigLoading && (
<>
{typeof loginConfig?.idps !== 'undefined' &&
loginConfig?.idps?.length > 0 && (
<div className={`${prefixCls}-other`}>
<FormattedMessage id="pages.login.login-with" />
</div>
)}
<Space className={`${prefixCls}-other-content`} align={'center'}>
{
// 不是短信和用户名密码时
currentProvider?.type !== IDP_TYPE.CAPTCHA &&
currentProvider?.type !== IDP_TYPE.ACCOUNT && (
<Tooltip
key={'password'}
title={intl.formatMessage({
id: 'pages.login.account-login.tab',
})}
placement="top"
>
<a
onClick={() => {
setCurrentProvider({
type: IDP_TYPE.ACCOUNT,
code: undefined,
});
}}
>
<Avatar
className={`${prefixCls}-other-avatar`}
size={50}
src={ICON_LIST.password}
/>
</a>
</Tooltip>
)
}
{loginConfig?.idps &&
loginConfig?.idps.map((value) => {
return (
value.code !== currentProvider?.code && (
<Tooltip key={nanoid()} title={value.name} placement="top">
<a
style={{ display: 'block' }}
onClick={() => {
setCurrentProvider({
type: IDP_TYPE.ACCOUNT,
code: undefined,
});
//钉钉OAuth认证跳转页面
if (value.type === IDP_TYPE.DINGTALK_OAUTH) {
dingTalkOauthOnClick(value.code);
return;
}
//飞书,跳转页面
if (value.type === IDP_TYPE.FEISHU_OAUTH) {
feiShuOauthOnClick(value.code);
return;
}
//QQ
if (value.type === IDP_TYPE.QQ_OAUTH) {
qqOauthOnClick(value.code);
return;
}
//微博
if (value.type === IDP_TYPE.WEIBO_OAUTH) {
weiBoOauthOnClick(value.code);
return;
}
//gitee
if (value.type === IDP_TYPE.GITEE_OAUTH) {
giteeOauthOnClick(value.code);
return;
}
//GITHUB跳转页面
if (value.type === IDP_TYPE.GITHUB_OAUTH) {
githubOauthOnClick(value.code);
return;
}
//支付宝,跳转页面
if (value.type === IDP_TYPE.ALIPAY_OAUTH) {
alipayOauthOnClick(value.code);
return;
}
//其他方式,跳转页面
else {
setCurrentProvider({
type: value.type,
code: value.code,
});
}
}}
>
<Avatar
className={`${prefixCls}-other-avatar`}
size={50}
src={ICON_LIST.password}
src={ICON_LIST[value.type]}
key={value.code}
/>
</a>
</Tooltip>
)
}
{loginConfig?.idps &&
loginConfig?.idps.map((value) => {
return (
value.code !== currentProvider?.code && (
<Tooltip key={nanoid()} title={value.name} placement="top">
<a
style={{ display: 'block' }}
onClick={() => {
//钉钉OAuth认证跳转页面
if (value.type === IDP_TYPE.DINGTALK_OAUTH) {
dingTalkOauthOnClick(value.code);
return;
}
//飞书,跳转页面
if (value.type === IDP_TYPE.FEISHU_OAUTH) {
feiShuOauthOnClick(value.code);
return;
}
//QQ
if (value.type === IDP_TYPE.QQ_OAUTH) {
qqOauthOnClick(value.code);
return;
}
//微博
if (value.type === IDP_TYPE.WEIBO_OAUTH) {
weiBoOauthOnClick(value.code);
return;
}
//gitee
if (value.type === IDP_TYPE.GITEE_OAUTH) {
giteeOauthOnClick(value.code);
return;
}
//GITHUB跳转页面
if (value.type === IDP_TYPE.GITHUB_OAUTH) {
githubOauthOnClick(value.code);
return;
}
//支付宝,跳转页面
if (value.type === IDP_TYPE.ALIPAY_OAUTH) {
alipayOauthOnClick(value.code);
return;
}
//其他方式,跳转页面
else {
setCurrentProvider({
type: value.type,
code: value.code,
});
}
}}
>
<Avatar
className={`${prefixCls}-other-avatar`}
size={50}
src={ICON_LIST[value.type]}
key={value.code}
/>
</a>
</Tooltip>
)
);
})}
</Space>
</>
)}
</Spin>
</>
</div>
</>
)}
{/**BIND USER*/}
{status === SESSION_STATUS.require_bind_idp && (
<div style={{ padding: '31px 38px 31px' }}>
<BindIdp />
);
})}
</Space>
</>
)}
</Spin>
</>
</div>
)}
{/*忘记密码*/}
{!status && forgetPassword && (
<ForgetPassword
close={() => {
setForgetPassword(false);
setStatusLoading(true);
setTimeout(() => {
setStatusLoading(false);
}, 85);
}}
/>
)}
</>
)}
</>
)}
{/**BIND USER*/}
{status === SESSION_STATUS.require_bind_idp && (
<div style={{ padding: '31px 38px 31px' }}>
<BindIdp />
</div>
)}
{/*忘记密码*/}
{!status && forgetPassword && (
<ForgetPassword
close={() => {
setForgetPassword(false);
setStatusLoading(true);
setTimeout(() => {
setStatusLoading(false);
}, 85);
}}
/>
)}
</div>
</div>
{/**Footer*/}
<Footer className={`${prefixCls}-footer`} />
</div>
{/**Footer*/}
<Footer className={`${prefixCls}-footer`} />
</div>
)}
</div>
);
};

View File

@ -21,8 +21,7 @@ const useStyle = createStyles((_, props) => {
const prefixCls = `${props}`;
return {
main: {
width: '320px',
marginTop: '24px',
width: '328px',
[`.${prefixCls}`]: {
['&-success-box']: {
padding: '40px',
@ -51,7 +50,6 @@ const useStyle = createStyles((_, props) => {
['&-back']: {
width: '100%',
marginBottom: '24px',
marginTop: '24px',
},
['&-back-time']: {
display: 'flex',

View File

@ -38,12 +38,11 @@ const useStyle = createStyles(({ prefixCls, token }, props) => {
display: 'flex',
flex: 'none !important',
flexDirection: 'column',
width: '430px',
padding: '32px',
maxWidth: '100%',
minHeight: '475px',
backgroundColor: '#fff',
borderRadius: token.borderRadius,
boxShadow: '0 2px 10px 0 rgb(57 106 255 / 5%)',
boxShadow: '0px 0px 24px 0px rgba(0,0,0,0.1)',
[`${antCls}-tabs-nav-list`]: {
margin: 'auto',
fontSize: '16px',
@ -57,7 +56,6 @@ const useStyle = createStyles(({ prefixCls, token }, props) => {
},
['&-top']: {
textAlign: 'center',
padding: '39px 0 0',
},
['&-logo']: {
width: '200px',
@ -68,7 +66,7 @@ const useStyle = createStyles(({ prefixCls, token }, props) => {
verticalAlign: 'top',
},
['&-desc']: {
marginTop: '12px',
marginTop: '25px',
marginBottom: '15px',
color: token.colorTextSecondary,
fontSize: token.fontSize,

View File

@ -24,7 +24,7 @@ const Workplace: FC = () => {
return (
<PageContainer>
<Card>
<Alert banner description={'欢迎使用 TopIAM 企业数字身份管控平台'} type={'success'} />
<Alert banner description={'欢迎使用 TOPIAM 企业数字身份管控平台'} type={'success'} />
</Card>
</PageContainer>
);