368 lines
14 KiB
TypeScript
368 lines
14 KiB
TypeScript
// @ts-nocheck
|
||
// Segmented这个对象在antd里的声明是错误的
|
||
import React, { useEffect, useState } from 'react';
|
||
import {
|
||
isMobile,
|
||
isPassword,
|
||
isCaptcha,
|
||
} from 'oak-domain/lib/utils/validator';
|
||
import { Form, Input, Button, Checkbox, Typography, Segmented, Divider, Space, Tooltip, Image } from 'antd';
|
||
import {
|
||
LockOutlined,
|
||
MobileOutlined,
|
||
QrcodeOutlined,
|
||
DesktopOutlined,
|
||
MailOutlined,
|
||
ExclamationCircleOutlined,
|
||
RightOutlined,
|
||
LinkOutlined,
|
||
} from '@ant-design/icons';
|
||
import { WebComponentProps } from 'oak-frontend-base';
|
||
import { EntityDict } from '../../../oak-app-domain';
|
||
|
||
import classNames from 'classnames';
|
||
import Style from './web.module.less';
|
||
import WeChatLoginQrCode from '../../common/weChatLoginQrCode';
|
||
import WechatLoginQrCodeForPublic from '../../wechatLogin/qrCode';
|
||
import WeChatLoginGrant from '../../common/weChatLoginGrant';
|
||
import SmsLogin from './sms';
|
||
import PasswordLogin from './password';
|
||
import EmailLogin from './email';
|
||
|
||
type Option = {
|
||
label: string;
|
||
value: string;
|
||
};
|
||
|
||
export default function Render(
|
||
props: WebComponentProps<
|
||
EntityDict,
|
||
'token',
|
||
false,
|
||
{
|
||
loginMode?: number;
|
||
appId: string;
|
||
loading: boolean;
|
||
width: string;
|
||
isSupportWechatGrant: boolean;
|
||
domain?: string;
|
||
disabled?: string;
|
||
redirectUri: string;
|
||
url: string;
|
||
passportTypes: EntityDict['passport']['Schema']['type'][];
|
||
callback: (() => void) | undefined;
|
||
inputOptions: Option[];
|
||
scanOptions: Option[];
|
||
smsDigit: number;
|
||
emailDigit: number;
|
||
pwdAllowMobile: boolean;
|
||
pwdAllowEmail: boolean;
|
||
pwdAllowLoginName: boolean;
|
||
pwdMode: 'all' | 'plain' | 'sha1';
|
||
allowRegister: boolean;
|
||
oauthOptions: {
|
||
name: string,
|
||
value: string,
|
||
logo?: string,
|
||
}[];
|
||
goRegister: () => void;
|
||
goOauthLogin: (oauthProviderId: string) => void;
|
||
},
|
||
{
|
||
setLoginMode: (value: number) => void;
|
||
}
|
||
>
|
||
) {
|
||
const { data, methods } = props;
|
||
const {
|
||
width,
|
||
loading,
|
||
loginMode,
|
||
appId,
|
||
domain,
|
||
isSupportWechatGrant,
|
||
disabled,
|
||
redirectUri,
|
||
url,
|
||
passportTypes,
|
||
callback,
|
||
inputOptions,
|
||
scanOptions,
|
||
smsDigit,
|
||
emailDigit,
|
||
pwdAllowMobile,
|
||
pwdAllowEmail,
|
||
pwdAllowLoginName,
|
||
pwdMode,
|
||
allowRegister,
|
||
oauthOptions,
|
||
goRegister,
|
||
goOauthLogin,
|
||
} = data;
|
||
const { t, setLoginMode, } = methods;
|
||
|
||
let redirectUri2 = redirectUri;
|
||
if (!(redirectUri.startsWith('https') || redirectUri.startsWith('http'))) {
|
||
const hostname = domain || window.location.hostname;
|
||
const port = window.location.port ? `:${window.location.port}` : '';
|
||
const path = redirectUri.startsWith('/') ? redirectUri : `/${redirectUri}`;
|
||
redirectUri2 = encodeURIComponent(
|
||
`${window.location.protocol}//${hostname}${port}${path}`
|
||
);
|
||
}
|
||
|
||
// 构建微信扫码所需state参数,url存在扫码后重定向url,否则返回上一页
|
||
let state = '';
|
||
if (url) {
|
||
state = encodeURIComponent(decodeURIComponent(url));
|
||
}
|
||
|
||
const [showInput, setShowInput] = useState(true);
|
||
useEffect(() => {
|
||
if (loginMode === 'sms' || loginMode === 'email' || loginMode === 'password') {
|
||
setShowInput(true)
|
||
} else {
|
||
setShowInput(false)
|
||
}
|
||
}, [loginMode]);
|
||
|
||
const InputMethods = inputOptions && inputOptions.length > 0 ? (
|
||
// <div className={Style['loginbox-methods']}>
|
||
// <Divider plain style={{ fontSize: 13, color: '#808080', }}>{t('otherMethods')}</Divider>
|
||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 24 }}>
|
||
{inputOptions.map((ele) => {
|
||
let icon = <></>;
|
||
if (ele.value === 'sms') {
|
||
icon = <MobileOutlined />;
|
||
} else if (ele.value === 'password') {
|
||
icon = <DesktopOutlined />;
|
||
} else if (ele.value === 'email') {
|
||
icon = <MailOutlined />;
|
||
}
|
||
return (
|
||
<Space
|
||
key={ele.value}
|
||
size={4}
|
||
style={{ cursor: 'pointer' }}
|
||
onClick={() => {
|
||
setLoginMode(ele.value)
|
||
}}
|
||
>
|
||
{icon}
|
||
<div>{ele.label}</div>
|
||
</Space>
|
||
)
|
||
})}
|
||
</div>
|
||
// </div>
|
||
) : <></>
|
||
|
||
const ScanMethods = scanOptions && scanOptions.length > 0 ? (
|
||
// <div className={Style['loginbox-methods']}>
|
||
// <Divider plain style={{ fontSize: 13, color: '#808080', }}>{t('otherMethods')}</Divider>
|
||
<Space
|
||
style={{ cursor: 'pointer' }}
|
||
onClick={() => {
|
||
setLoginMode(scanOptions[0].value)
|
||
}}
|
||
>
|
||
<QrcodeOutlined />
|
||
<div>{t('scanLogin')}</div>
|
||
</Space>
|
||
// </div>
|
||
) : <></>
|
||
|
||
const OauthMethods = oauthOptions && oauthOptions.length > 0 ? (
|
||
// <div className={Style['loginbox-methods']}>
|
||
// <Divider plain style={{ fontSize: 13, color: '#808080', }}>{t('otherMethods')}</Divider>
|
||
<Space
|
||
style={{ cursor: 'pointer' }}
|
||
>
|
||
{oauthOptions?.map((ele) => (
|
||
<Tooltip title={ele.name}>
|
||
<Image
|
||
preview={false}
|
||
width={20}
|
||
height={20}
|
||
src={ele.logo}
|
||
onClick={() => {
|
||
goOauthLogin(ele.value)
|
||
}}
|
||
placeholder={<LinkOutlined />}
|
||
/>
|
||
</Tooltip>
|
||
))}
|
||
</Space>
|
||
// </div>
|
||
) : <></>
|
||
|
||
const Tip = <div className={Style['loginbox-tip']}>
|
||
<Space>
|
||
<ExclamationCircleOutlined />
|
||
<div>{t('tip')}</div>
|
||
</Space>
|
||
</div>
|
||
|
||
return (
|
||
<div
|
||
className={classNames(Style['loginbox-wrap'], {
|
||
[Style['loginbox-wrap__mobile']]: width === 'xs',
|
||
})}
|
||
>
|
||
<div className={Style['loginbox-hd']}>
|
||
<Segmented
|
||
className={Style.segmented}
|
||
value={loginMode}
|
||
block
|
||
onChange={setLoginMode}
|
||
options={showInput ? inputOptions.map((ele) => ({
|
||
label: ele.label,
|
||
value: ele.value,
|
||
})) : scanOptions.map((ele) => ({
|
||
label: ele.label,
|
||
value: ele.value,
|
||
}))}
|
||
></Segmented>
|
||
</div>
|
||
|
||
<div
|
||
className={classNames(Style['loginbox-bd'], {
|
||
[Style['loginbox-bd__grant']]: isSupportWechatGrant,
|
||
})}
|
||
>
|
||
{isSupportWechatGrant ? (
|
||
<div className={Style['loginbox-grant']}>
|
||
<WeChatLoginGrant
|
||
disabled={!!disabled}
|
||
disableText={disabled}
|
||
appId={appId}
|
||
scope="snsapi_userinfo"
|
||
redirectUri={redirectUri2}
|
||
state={state}
|
||
/>
|
||
</div>
|
||
) : (
|
||
<>
|
||
{showInput ? (
|
||
<>
|
||
<div
|
||
className={Style['loginbox-password']}
|
||
style={{
|
||
display: loginMode === 'password' ? 'block' : 'none',
|
||
}}
|
||
>
|
||
<PasswordLogin
|
||
disabled={disabled}
|
||
url={url}
|
||
callback={callback}
|
||
pwdAllowMobile={pwdAllowMobile}
|
||
pwdAllowEmail={pwdAllowEmail}
|
||
pwdAllowLoginName={pwdAllowLoginName}
|
||
pwdMode={pwdMode}
|
||
/>
|
||
{allowRegister && (
|
||
<div className={Style['loginbox-register']}>
|
||
{/* <Button type='link' iconPosition='end' icon={<RightOutlined />}>去注册</Button> */}
|
||
<Button type='link' onClick={() => {
|
||
goRegister && goRegister()
|
||
}}>{`${t('goRegister')} >`}</Button>
|
||
</div>
|
||
)}
|
||
</div>
|
||
<div
|
||
className={Style['loginbox-mobile']}
|
||
style={{
|
||
display: loginMode === 'sms' ? 'block' : 'none',
|
||
}}
|
||
>
|
||
<SmsLogin
|
||
disabled={disabled}
|
||
url={url}
|
||
callback={callback}
|
||
digit={smsDigit}
|
||
/>
|
||
{Tip}
|
||
</div>
|
||
<div
|
||
className={Style['loginbox-email']}
|
||
style={{
|
||
display: loginMode === 'email' ? 'block' : 'none',
|
||
}}
|
||
>
|
||
<EmailLogin
|
||
disabled={disabled}
|
||
url={url}
|
||
callback={callback}
|
||
digit={emailDigit}
|
||
/>
|
||
{Tip}
|
||
</div>
|
||
{(scanOptions?.length > 0 || oauthOptions?.length > 0) ? (
|
||
<div className={Style['loginbox-methods']}>
|
||
<Divider plain style={{ fontSize: 13, color: '#808080', }}>{t('otherMethods')}</Divider>
|
||
<Space split={<Divider type="vertical" />}>
|
||
{ScanMethods}
|
||
{OauthMethods}
|
||
</Space>
|
||
</div>
|
||
) : (<></>)}
|
||
</>
|
||
) : (
|
||
<>
|
||
{loginMode === 'wechatWeb' &&
|
||
<div
|
||
className={Style['loginbox-qrcode']}
|
||
>
|
||
<WeChatLoginQrCode
|
||
disabled={!!disabled}
|
||
disableText={disabled}
|
||
appId={appId}
|
||
scope="snsapi_login"
|
||
redirectUri={redirectUri2}
|
||
state={state}
|
||
/>
|
||
{Tip}
|
||
</div>}
|
||
{loginMode === 'wechatPublicForWeb' && <div
|
||
className={Style['loginbox-qrcode']}
|
||
>
|
||
<WechatLoginQrCodeForPublic
|
||
type="login"
|
||
oakPath="$login-wechatLogin/qrCode"
|
||
oakAutoUnmount={true}
|
||
url={state}
|
||
size={180}
|
||
/>
|
||
{Tip}
|
||
</div>}
|
||
{loginMode === 'wechatMpForWeb' && <div
|
||
className={Style['loginbox-qrcode']}
|
||
>
|
||
<WechatLoginQrCodeForPublic
|
||
type="login"
|
||
oakPath="$login-wechatLogin/qrCode"
|
||
oakAutoUnmount={true}
|
||
url={state}
|
||
size={180}
|
||
qrCodeType={'wechatMpDomainUrl'}
|
||
/>
|
||
{Tip}
|
||
</div>}
|
||
{(inputOptions?.length > 0 || oauthOptions?.length > 0) ? (
|
||
<div className={Style['loginbox-methods']}>
|
||
<Divider plain style={{ fontSize: 13, color: '#808080', }}>{t('otherMethods')}</Divider>
|
||
<Space split={<Divider type="vertical" />}>
|
||
{InputMethods}
|
||
{OauthMethods}
|
||
</Space>
|
||
</div>
|
||
) : (<></>)}
|
||
</>
|
||
)}
|
||
</>
|
||
)}
|
||
</div>
|
||
</div >
|
||
);
|
||
}
|