登录修改
This commit is contained in:
parent
a39d4e2311
commit
8a258d55d4
|
|
@ -8,9 +8,10 @@
|
|||
}
|
||||
|
||||
&_dev {
|
||||
height: 280px;
|
||||
// height: 280px;
|
||||
border: 1px dashed var(--oak-color-primary);
|
||||
padding: 10px;
|
||||
margin-bottom: 12px;
|
||||
|
||||
&_header {
|
||||
display: flex;
|
||||
|
|
@ -36,7 +37,7 @@
|
|||
}
|
||||
|
||||
&_btn {
|
||||
margin-top: 16px;
|
||||
// margin-top: 16px;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 40px;
|
||||
|
|
@ -102,16 +103,16 @@
|
|||
|
||||
&_disable {
|
||||
&_border {
|
||||
height: 202px;
|
||||
width: 202px;
|
||||
margin: 15px;
|
||||
height: 220px;
|
||||
width: 220px;
|
||||
// margin: 15px;
|
||||
background-color: #f5f7fa;
|
||||
color: rgba(0, 0, 0, .4);
|
||||
font-size: 14px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
padding: 15px;
|
||||
// padding: 15px;
|
||||
}
|
||||
|
||||
&_info {
|
||||
|
|
@ -124,7 +125,7 @@
|
|||
}
|
||||
|
||||
&_err {
|
||||
height: 280px;
|
||||
// height: 280px;
|
||||
border: 1px dashed var(--oak-color-primary);
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@ export default OakComponent({
|
|||
isSupportWechatGrant: false,
|
||||
domain: undefined,
|
||||
passportTypes: [],
|
||||
options: [],
|
||||
inputOptions: [],
|
||||
scanOptions: [],
|
||||
allowSms: false,
|
||||
allowPassword: false,
|
||||
allowWechatMp: false,
|
||||
|
|
@ -28,38 +29,44 @@ export default OakComponent({
|
|||
return {};
|
||||
},
|
||||
listeners: {
|
||||
'onlyPassword,onlyCaptcha'(prev, next) {
|
||||
let loginMode = this.state.loginMode, options = this.state.options;
|
||||
if (next.onlyPassword) {
|
||||
loginMode = 'password';
|
||||
options = [{
|
||||
label: this.t('passport:v.type.password'),
|
||||
value: 'password',
|
||||
}];
|
||||
}
|
||||
else if (next.onlyCaptcha) {
|
||||
loginMode = 'sms';
|
||||
options = [{
|
||||
label: this.t('passport:v.type.sms'),
|
||||
value: 'sms',
|
||||
}];
|
||||
}
|
||||
else {
|
||||
const { passportTypes } = this.state;
|
||||
if (passportTypes && passportTypes.length > 0) {
|
||||
passportTypes.forEach((ele) => {
|
||||
options.push({
|
||||
label: this.t(`passport:v.type.${ele}`),
|
||||
value: ele
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
this.setState({
|
||||
loginMode,
|
||||
options,
|
||||
});
|
||||
}
|
||||
// 'onlyPassword,onlyCaptcha'(prev, next) {
|
||||
// let loginMode = this.state.loginMode, inputOptions = this.state.inputOptions, scanOptions = this.state.scanOptions;
|
||||
// if (next.onlyPassword) {
|
||||
// loginMode = 'password';
|
||||
// inputOptions = [{
|
||||
// label: this.t('passport:v.type.password'),
|
||||
// value: 'password',
|
||||
// }];
|
||||
// } else if (next.onlyCaptcha) {
|
||||
// loginMode = 'sms';
|
||||
// inputOptions = [{
|
||||
// label: this.t('passport:v.type.sms'),
|
||||
// value: 'sms',
|
||||
// }];
|
||||
// } else {
|
||||
// const { passportTypes } = this.state;
|
||||
// if (passportTypes && passportTypes.length > 0) {
|
||||
// passportTypes.forEach((ele: EntityDict['passport']['Schema']['type']) => {
|
||||
// if (ele === 'sms' || ele === 'email' || ele === 'password') {
|
||||
// inputOptions.push({
|
||||
// label: this.t(`passport:v.type.${ele}`),
|
||||
// value: ele
|
||||
// })
|
||||
// } else if (ele === 'wechatMpForWeb' || ele === 'wechatPublicForWeb') {
|
||||
// scanOptions.push({
|
||||
// label: this.t(`passport:v.type.${ele}`),
|
||||
// value: ele
|
||||
// })
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
// this.setState({
|
||||
// loginMode,
|
||||
// inputOptions,
|
||||
// scanOptions,
|
||||
// })
|
||||
// }
|
||||
},
|
||||
lifetimes: {
|
||||
async ready() {
|
||||
|
|
@ -67,30 +74,42 @@ export default OakComponent({
|
|||
const { result: applicationPassports } = await this.features.cache.exec('getApplicationPassports', { applicationId: application.id });
|
||||
const defaultPassport = applicationPassports.find((ele) => ele.isDefault);
|
||||
const passportTypes = applicationPassports.map((ele) => ele.passport.type);
|
||||
const { onlyCaptcha, onlyPassword } = this.props;
|
||||
let loginMode = (await this.load(LOGIN_MODE)) || defaultPassport.passport.type;
|
||||
let options = [];
|
||||
if (this.props.onlyPassword) {
|
||||
let inputOptions = [], scanOptions = [];
|
||||
if (onlyPassword) {
|
||||
loginMode = 'password';
|
||||
options = [{
|
||||
label: this.t('passport:v.type.password'),
|
||||
inputOptions = [{
|
||||
label: this.t('passport:v.type.password') + this.t('Login'),
|
||||
value: 'password',
|
||||
}];
|
||||
}
|
||||
else if (this.props.onlyCaptcha) {
|
||||
else if (onlyCaptcha) {
|
||||
loginMode = 'sms';
|
||||
options = [{
|
||||
label: this.t('passport:v.type.sms'),
|
||||
inputOptions = [{
|
||||
label: this.t('passport:v.type.sms') + this.t('Login'),
|
||||
value: 'sms',
|
||||
}];
|
||||
}
|
||||
else {
|
||||
passportTypes.forEach((ele) => {
|
||||
options.push({
|
||||
label: this.t(`passport:v.type.${ele}`),
|
||||
value: ele
|
||||
});
|
||||
if (ele === 'sms' || ele === 'email' || ele === 'password') {
|
||||
inputOptions.push({
|
||||
label: this.t(`passport:v.type.${ele}`) + this.t('Login'),
|
||||
value: ele
|
||||
});
|
||||
}
|
||||
else if (ele === 'wechatWeb' || ele === 'wechatMpForWeb' || ele === 'wechatPublicForWeb') {
|
||||
scanOptions.push({
|
||||
label: this.t(`passport:v.type.${ele}`) + this.t('Login'),
|
||||
value: ele
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!passportTypes.includes(loginMode)) {
|
||||
loginMode = defaultPassport.passport.type;
|
||||
}
|
||||
const appType = application?.type;
|
||||
const config = application?.config;
|
||||
let appId;
|
||||
|
|
@ -109,9 +128,9 @@ export default OakComponent({
|
|||
domain = config2?.wechat?.domain;
|
||||
}
|
||||
else if (appType === 'wechatMp') {
|
||||
allowSms = passportTypes.includes('sms');
|
||||
allowPassword = passportTypes.includes('password');
|
||||
allowWechatMp = passportTypes.includes('wechatMp');
|
||||
allowSms = passportTypes.includes('sms') && !onlyPassword;
|
||||
allowPassword = passportTypes.includes('password') && !onlyCaptcha;
|
||||
allowWechatMp = passportTypes.includes('wechatMp') && !onlyCaptcha && !onlyPassword;
|
||||
}
|
||||
this.setState({
|
||||
loginMode,
|
||||
|
|
@ -119,7 +138,8 @@ export default OakComponent({
|
|||
isSupportWechatGrant,
|
||||
domain,
|
||||
passportTypes,
|
||||
options,
|
||||
inputOptions,
|
||||
scanOptions,
|
||||
allowSms,
|
||||
allowPassword,
|
||||
allowWechatMp,
|
||||
|
|
|
|||
|
|
@ -10,5 +10,8 @@
|
|||
"Mobile": "请输入手机号",
|
||||
"Password": "请输入密码"
|
||||
},
|
||||
"resendAfter": "秒后可重发"
|
||||
"resendAfter": "秒后可重发",
|
||||
"otherMethods": "其他登录方式",
|
||||
"scanLogin": "扫码登录",
|
||||
"tip": "未注册用户首次登录将自动注册"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,8 @@ export default function Render(props: WebComponentProps<EntityDict, 'token', fal
|
|||
url: string;
|
||||
passportTypes: EntityDict['passport']['Schema']['type'][];
|
||||
callback: (() => void) | undefined;
|
||||
options: Option[];
|
||||
inputOptions: Option[];
|
||||
scanOptions: Option[];
|
||||
}, {
|
||||
setLoginMode: (value: number) => void;
|
||||
}>): React.JSX.Element;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
// @ts-nocheck
|
||||
// Segmented这个对象在antd里的声明是错误的
|
||||
import React from 'react';
|
||||
import { Segmented } from 'antd';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Segmented, Divider, Space } from 'antd';
|
||||
import { MobileOutlined, QrcodeOutlined, DesktopOutlined, MailOutlined, ExclamationCircleOutlined, } from '@ant-design/icons';
|
||||
import classNames from 'classnames';
|
||||
import Style from './web.module.less';
|
||||
import WeChatLoginQrCode from '../../common/weChatLoginQrCode';
|
||||
|
|
@ -11,7 +12,7 @@ import SmsLogin from './sms';
|
|||
import PasswordLogin from './password';
|
||||
export default function Render(props) {
|
||||
const { data, methods } = props;
|
||||
const { width, loading, loginMode, appId, domain, isSupportWechatGrant, disabled, redirectUri, url, passportTypes, callback, options, } = data;
|
||||
const { width, loading, loginMode, appId, domain, isSupportWechatGrant, disabled, redirectUri, url, passportTypes, callback, inputOptions, scanOptions, } = data;
|
||||
const { t, setLoginMode } = methods;
|
||||
let redirectUri2 = redirectUri;
|
||||
if (!(redirectUri.startsWith('https') || redirectUri.startsWith('http'))) {
|
||||
|
|
@ -25,15 +26,65 @@ export default function Render(props) {
|
|||
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 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 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',
|
||||
})}>
|
||||
{options?.length > 1 ? (<div className={Style['loginbox-hd']}>
|
||||
<Segmented className={Style.segmented} value={loginMode} block onChange={setLoginMode} options={options.map((ele) => ({
|
||||
label: ele.label,
|
||||
value: ele.value,
|
||||
}))}></Segmented>
|
||||
</div>) : (<div className={Style['loginbox-hd']}></div>)}
|
||||
<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,
|
||||
|
|
@ -41,22 +92,32 @@ export default function Render(props) {
|
|||
{isSupportWechatGrant ? (<div className={Style['loginbox-grant']}>
|
||||
<WeChatLoginGrant disabled={!!disabled} disableText={disabled} appId={appId} scope="snsapi_userinfo" redirectUri={redirectUri2} state={state}/>
|
||||
</div>) : (<>
|
||||
<div className={Style['loginbox-password']} style={{
|
||||
display: loginMode === 'password' ? 'block' : 'none',
|
||||
}}>
|
||||
<PasswordLogin disabled={disabled} url={url} callback={callback}/>
|
||||
</div>
|
||||
<div className={Style['loginbox-mobile']} style={{
|
||||
display: loginMode === 'sms' ? 'block' : 'none',
|
||||
}}>
|
||||
<SmsLogin disabled={disabled} url={url} callback={callback}/>
|
||||
</div>
|
||||
{loginMode === 'wechatWeb' && <div className={Style['loginbox-qrcode']}>
|
||||
<WeChatLoginQrCode disabled={!!disabled} disableText={disabled} appId={appId} scope="snsapi_login" redirectUri={redirectUri2} state={state}/>
|
||||
</div>}
|
||||
{loginMode === 'wechatPublicForWeb' && <div className={Style['loginbox-qrcode']}>
|
||||
<WechatLoginQrCodeForPublic type="login" oakPath="$login-wechatLogin/qrCode" oakAutoUnmount={true} url={state}/>
|
||||
</div>}
|
||||
{showInput ? (<>
|
||||
<div className={Style['loginbox-password']} style={{
|
||||
display: loginMode === 'password' ? 'block' : 'none',
|
||||
}}>
|
||||
<PasswordLogin disabled={disabled} url={url} callback={callback}/>
|
||||
{Tip}
|
||||
</div>
|
||||
<div className={Style['loginbox-mobile']} style={{
|
||||
display: loginMode === 'sms' ? 'block' : 'none',
|
||||
}}>
|
||||
<SmsLogin disabled={disabled} url={url} callback={callback}/>
|
||||
{Tip}
|
||||
</div>
|
||||
{ScanMethods}
|
||||
</>) : (<>
|
||||
{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={200}/>
|
||||
{Tip}
|
||||
</div>}
|
||||
{InputMethods}
|
||||
</>)}
|
||||
</>)}
|
||||
</div>
|
||||
</div>);
|
||||
|
|
|
|||
|
|
@ -21,14 +21,16 @@
|
|||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 4px rgb(0 0 0 / 8%), 0 0 4px rgb(0 0 0 / 8%);
|
||||
transition: all 0.5s;
|
||||
}
|
||||
|
||||
&-hd {
|
||||
padding: 32px;
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
|
||||
&-bd {
|
||||
height: 310px;
|
||||
min-height: 320px;
|
||||
}
|
||||
|
||||
&-only {
|
||||
|
|
@ -37,17 +39,21 @@
|
|||
|
||||
&-mobile {
|
||||
position: relative;
|
||||
padding: 0 32px;
|
||||
padding: 32px;
|
||||
height: 220px;
|
||||
}
|
||||
|
||||
&-password {
|
||||
position: relative;
|
||||
padding: 0 32px;
|
||||
padding: 32px;
|
||||
height: 220px;
|
||||
}
|
||||
|
||||
&-qrcode {
|
||||
padding: 0 32px;
|
||||
font-size: 14px;
|
||||
height: 268px;
|
||||
padding-top: 16px;
|
||||
|
||||
&__sociallogin {
|
||||
text-align: center;
|
||||
|
|
@ -95,4 +101,23 @@
|
|||
cursor: default;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
&-methods {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0px 24px 16px 24px;
|
||||
font-size: 13px;
|
||||
color: #6c7d8f;
|
||||
}
|
||||
|
||||
&-tip {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 13px;
|
||||
color: #808080;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
import { EntityDict } from '../../../oak-app-domain';
|
||||
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<EntityDict, keyof EntityDict, false, {
|
||||
type: "login" | "bind";
|
||||
type: "bind" | "login";
|
||||
url: string;
|
||||
size: undefined;
|
||||
}>) => React.ReactElement;
|
||||
export default _default;
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ export default OakComponent({
|
|||
properties: {
|
||||
type: 'bind',
|
||||
url: '',
|
||||
size: undefined,
|
||||
},
|
||||
methods: {
|
||||
async createWechatLogin() {
|
||||
|
|
|
|||
|
|
@ -7,4 +7,5 @@ export default function Render(props: WebComponentProps<EntityDict, 'wechatLogin
|
|||
loading: boolean;
|
||||
successful: boolean;
|
||||
type: EntityDict['wechatLogin']['Schema']['type'];
|
||||
size: number;
|
||||
}, {}>): React.JSX.Element;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import React from 'react';
|
||||
import QrCode from '../../../components/common/qrCode';
|
||||
export default function Render(props) {
|
||||
const { oakFullpath, qrCodeUrl, loading, successful, type } = props.data;
|
||||
const { oakFullpath, qrCodeUrl, loading, successful, type, size } = props.data;
|
||||
return (<div>
|
||||
<QrCode loading={loading} url={qrCodeUrl} disableDownload={true} tips={<div>微信扫一扫</div>} successful={successful} type={type}/>
|
||||
<QrCode loading={loading} url={qrCodeUrl} disableDownload={true} tips={<div>微信扫一扫</div>} successful={successful} type={type} size={size}/>
|
||||
</div>);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -317,7 +317,10 @@ const i18ns = [
|
|||
"Mobile": "请输入手机号",
|
||||
"Password": "请输入密码"
|
||||
},
|
||||
"resendAfter": "秒后可重发"
|
||||
"resendAfter": "秒后可重发",
|
||||
"otherMethods": "其他登录方式",
|
||||
"scanLogin": "扫码登录",
|
||||
"tip": "未注册用户首次登录将自动注册"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -319,7 +319,10 @@ const i18ns = [
|
|||
"Mobile": "请输入手机号",
|
||||
"Password": "请输入密码"
|
||||
},
|
||||
"resendAfter": "秒后可重发"
|
||||
"resendAfter": "秒后可重发",
|
||||
"otherMethods": "其他登录方式",
|
||||
"scanLogin": "扫码登录",
|
||||
"tip": "未注册用户首次登录将自动注册"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -8,9 +8,10 @@
|
|||
}
|
||||
|
||||
&_dev {
|
||||
height: 280px;
|
||||
// height: 280px;
|
||||
border: 1px dashed var(--oak-color-primary);
|
||||
padding: 10px;
|
||||
margin-bottom: 12px;
|
||||
|
||||
&_header {
|
||||
display: flex;
|
||||
|
|
@ -36,7 +37,7 @@
|
|||
}
|
||||
|
||||
&_btn {
|
||||
margin-top: 16px;
|
||||
// margin-top: 16px;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 40px;
|
||||
|
|
@ -102,16 +103,16 @@
|
|||
|
||||
&_disable {
|
||||
&_border {
|
||||
height: 202px;
|
||||
width: 202px;
|
||||
margin: 15px;
|
||||
height: 220px;
|
||||
width: 220px;
|
||||
// margin: 15px;
|
||||
background-color: #f5f7fa;
|
||||
color: rgba(0, 0, 0, .4);
|
||||
font-size: 14px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
padding: 15px;
|
||||
// padding: 15px;
|
||||
}
|
||||
|
||||
&_info {
|
||||
|
|
@ -124,7 +125,7 @@
|
|||
}
|
||||
|
||||
&_err {
|
||||
height: 280px;
|
||||
// height: 280px;
|
||||
border: 1px dashed var(--oak-color-primary);
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
|
|
|
|||
|
|
@ -19,7 +19,8 @@ export default OakComponent({
|
|||
isSupportWechatGrant: false,
|
||||
domain: undefined as string | undefined,
|
||||
passportTypes: [] as EntityDict['passport']['Schema']['type'][],
|
||||
options: [] as Option[],
|
||||
inputOptions: [] as Option[],
|
||||
scanOptions: [] as Option[],
|
||||
allowSms: false,
|
||||
allowPassword: false,
|
||||
allowWechatMp: false,
|
||||
|
|
@ -37,36 +38,44 @@ export default OakComponent({
|
|||
return {};
|
||||
},
|
||||
listeners: {
|
||||
'onlyPassword,onlyCaptcha'(prev, next) {
|
||||
let loginMode = this.state.loginMode, options = this.state.options;
|
||||
if (next.onlyPassword) {
|
||||
loginMode = 'password';
|
||||
options = [{
|
||||
label: this.t('passport:v.type.password'),
|
||||
value: 'password',
|
||||
}];
|
||||
} else if (next.onlyCaptcha) {
|
||||
loginMode = 'sms';
|
||||
options = [{
|
||||
label: this.t('passport:v.type.sms'),
|
||||
value: 'sms',
|
||||
}];
|
||||
} else {
|
||||
const { passportTypes } = this.state;
|
||||
if (passportTypes && passportTypes.length > 0) {
|
||||
passportTypes.forEach((ele: EntityDict['passport']['Schema']['type']) => {
|
||||
options.push({
|
||||
label: this.t(`passport:v.type.${ele}`),
|
||||
value: ele
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
this.setState({
|
||||
loginMode,
|
||||
options,
|
||||
})
|
||||
}
|
||||
// 'onlyPassword,onlyCaptcha'(prev, next) {
|
||||
// let loginMode = this.state.loginMode, inputOptions = this.state.inputOptions, scanOptions = this.state.scanOptions;
|
||||
// if (next.onlyPassword) {
|
||||
// loginMode = 'password';
|
||||
// inputOptions = [{
|
||||
// label: this.t('passport:v.type.password'),
|
||||
// value: 'password',
|
||||
// }];
|
||||
// } else if (next.onlyCaptcha) {
|
||||
// loginMode = 'sms';
|
||||
// inputOptions = [{
|
||||
// label: this.t('passport:v.type.sms'),
|
||||
// value: 'sms',
|
||||
// }];
|
||||
// } else {
|
||||
// const { passportTypes } = this.state;
|
||||
// if (passportTypes && passportTypes.length > 0) {
|
||||
// passportTypes.forEach((ele: EntityDict['passport']['Schema']['type']) => {
|
||||
// if (ele === 'sms' || ele === 'email' || ele === 'password') {
|
||||
// inputOptions.push({
|
||||
// label: this.t(`passport:v.type.${ele}`),
|
||||
// value: ele
|
||||
// })
|
||||
// } else if (ele === 'wechatMpForWeb' || ele === 'wechatPublicForWeb') {
|
||||
// scanOptions.push({
|
||||
// label: this.t(`passport:v.type.${ele}`),
|
||||
// value: ele
|
||||
// })
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
// this.setState({
|
||||
// loginMode,
|
||||
// inputOptions,
|
||||
// scanOptions,
|
||||
// })
|
||||
// }
|
||||
},
|
||||
lifetimes: {
|
||||
async ready() {
|
||||
|
|
@ -75,29 +84,42 @@ export default OakComponent({
|
|||
const defaultPassport = applicationPassports.find((ele: EntityDict['applicationPassport']['Schema']) => ele.isDefault);
|
||||
const passportTypes = applicationPassports.map((ele: EntityDict['applicationPassport']['Schema']) => ele.passport.type);
|
||||
|
||||
const { onlyCaptcha, onlyPassword } = this.props;
|
||||
|
||||
let loginMode = (await this.load(LOGIN_MODE)) || defaultPassport.passport.type;
|
||||
let options: Option[] = [];
|
||||
if (this.props.onlyPassword) {
|
||||
let inputOptions: Option[] = [], scanOptions: Option[] = [];
|
||||
if (onlyPassword) {
|
||||
loginMode = 'password';
|
||||
options = [{
|
||||
label: this.t('passport:v.type.password'),
|
||||
inputOptions = [{
|
||||
label: this.t('passport:v.type.password') + this.t('Login'),
|
||||
value: 'password',
|
||||
}];
|
||||
} else if (this.props.onlyCaptcha) {
|
||||
} else if (onlyCaptcha) {
|
||||
loginMode = 'sms';
|
||||
options = [{
|
||||
label: this.t('passport:v.type.sms'),
|
||||
inputOptions = [{
|
||||
label: this.t('passport:v.type.sms') + this.t('Login'),
|
||||
value: 'sms',
|
||||
}];
|
||||
} else {
|
||||
passportTypes.forEach((ele: EntityDict['passport']['Schema']['type']) => {
|
||||
options.push({
|
||||
label: this.t(`passport:v.type.${ele}`),
|
||||
value: ele
|
||||
})
|
||||
if (ele === 'sms' || ele === 'email' || ele === 'password') {
|
||||
inputOptions.push({
|
||||
label: this.t(`passport:v.type.${ele}`) + this.t('Login'),
|
||||
value: ele
|
||||
})
|
||||
} else if (ele === 'wechatWeb' || ele === 'wechatMpForWeb' || ele === 'wechatPublicForWeb') {
|
||||
scanOptions.push({
|
||||
label: this.t(`passport:v.type.${ele}`) + this.t('Login'),
|
||||
value: ele
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!passportTypes.includes(loginMode)) {
|
||||
loginMode = defaultPassport.passport.type;
|
||||
}
|
||||
|
||||
const appType = application?.type as AppType;
|
||||
const config = application?.config;
|
||||
let appId;
|
||||
|
|
@ -114,9 +136,9 @@ export default OakComponent({
|
|||
appId = config2?.wechat?.appId;
|
||||
domain = config2?.wechat?.domain;
|
||||
} else if (appType === 'wechatMp') {
|
||||
allowSms = passportTypes.includes('sms');
|
||||
allowPassword = passportTypes.includes('password');
|
||||
allowWechatMp = passportTypes.includes('wechatMp');
|
||||
allowSms = passportTypes.includes('sms') && !onlyPassword;
|
||||
allowPassword = passportTypes.includes('password') && !onlyCaptcha;
|
||||
allowWechatMp = passportTypes.includes('wechatMp') && !onlyCaptcha && !onlyPassword;
|
||||
}
|
||||
|
||||
this.setState(
|
||||
|
|
@ -126,7 +148,8 @@ export default OakComponent({
|
|||
isSupportWechatGrant,
|
||||
domain,
|
||||
passportTypes,
|
||||
options,
|
||||
inputOptions,
|
||||
scanOptions,
|
||||
allowSms,
|
||||
allowPassword,
|
||||
allowWechatMp,
|
||||
|
|
|
|||
|
|
@ -10,5 +10,8 @@
|
|||
"Mobile": "请输入手机号",
|
||||
"Password": "请输入密码"
|
||||
},
|
||||
"resendAfter": "秒后可重发"
|
||||
}
|
||||
"resendAfter": "秒后可重发",
|
||||
"otherMethods": "其他登录方式",
|
||||
"scanLogin": "扫码登录",
|
||||
"tip": "未注册用户首次登录将自动注册"
|
||||
}
|
||||
|
|
@ -21,14 +21,16 @@
|
|||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 4px rgb(0 0 0 / 8%), 0 0 4px rgb(0 0 0 / 8%);
|
||||
transition: all 0.5s;
|
||||
}
|
||||
|
||||
&-hd {
|
||||
padding: 32px;
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
|
||||
&-bd {
|
||||
height: 310px;
|
||||
min-height: 320px;
|
||||
}
|
||||
|
||||
&-only {
|
||||
|
|
@ -37,17 +39,21 @@
|
|||
|
||||
&-mobile {
|
||||
position: relative;
|
||||
padding: 0 32px;
|
||||
padding: 32px;
|
||||
height: 220px;
|
||||
}
|
||||
|
||||
&-password {
|
||||
position: relative;
|
||||
padding: 0 32px;
|
||||
padding: 32px;
|
||||
height: 220px;
|
||||
}
|
||||
|
||||
&-qrcode {
|
||||
padding: 0 32px;
|
||||
font-size: 14px;
|
||||
height: 268px;
|
||||
padding-top: 16px;
|
||||
|
||||
&__sociallogin {
|
||||
text-align: center;
|
||||
|
|
@ -95,4 +101,23 @@
|
|||
cursor: default;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
&-methods {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0px 24px 16px 24px;
|
||||
font-size: 13px;
|
||||
color: #6c7d8f;
|
||||
}
|
||||
|
||||
&-tip {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 13px;
|
||||
color: #808080;
|
||||
}
|
||||
}
|
||||
|
|
@ -6,10 +6,14 @@ import {
|
|||
isPassword,
|
||||
isCaptcha,
|
||||
} from 'oak-domain/lib/utils/validator';
|
||||
import { Form, Input, Button, Checkbox, Typography, Segmented } from 'antd';
|
||||
import { Form, Input, Button, Checkbox, Typography, Segmented, Divider, Space } from 'antd';
|
||||
import {
|
||||
LockOutlined,
|
||||
MobileOutlined,
|
||||
QrcodeOutlined,
|
||||
DesktopOutlined,
|
||||
MailOutlined,
|
||||
ExclamationCircleOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import { WebComponentProps } from 'oak-frontend-base';
|
||||
import { EntityDict } from '../../../oak-app-domain';
|
||||
|
|
@ -44,7 +48,8 @@ export default function Render(
|
|||
url: string;
|
||||
passportTypes: EntityDict['passport']['Schema']['type'][];
|
||||
callback: (() => void) | undefined;
|
||||
options: Option[];
|
||||
inputOptions: Option[];
|
||||
scanOptions: Option[];
|
||||
},
|
||||
{
|
||||
setLoginMode: (value: number) => void;
|
||||
|
|
@ -64,7 +69,8 @@ export default function Render(
|
|||
url,
|
||||
passportTypes,
|
||||
callback,
|
||||
options,
|
||||
inputOptions,
|
||||
scanOptions,
|
||||
} = data;
|
||||
const { t, setLoginMode } = methods;
|
||||
|
||||
|
|
@ -84,28 +90,88 @@ export default function Render(
|
|||
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
|
||||
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 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',
|
||||
})}
|
||||
>
|
||||
{options?.length > 1 ? (
|
||||
<div className={Style['loginbox-hd']}>
|
||||
<Segmented
|
||||
className={Style.segmented}
|
||||
value={loginMode}
|
||||
block
|
||||
onChange={setLoginMode}
|
||||
options={options.map((ele) => ({
|
||||
label: ele.label,
|
||||
value: ele.value,
|
||||
}))}
|
||||
></Segmented>
|
||||
</div>
|
||||
) : (
|
||||
<div className={Style['loginbox-hd']}></div>
|
||||
)}
|
||||
<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'], {
|
||||
|
|
@ -125,55 +191,70 @@ export default function Render(
|
|||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div
|
||||
className={Style['loginbox-password']}
|
||||
style={{
|
||||
display: loginMode === 'password' ? 'block' : 'none',
|
||||
}}
|
||||
>
|
||||
<PasswordLogin
|
||||
disabled={disabled}
|
||||
url={url}
|
||||
callback={callback}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className={Style['loginbox-mobile']}
|
||||
style={{
|
||||
display: loginMode === 'sms' ? 'block' : 'none',
|
||||
}}
|
||||
>
|
||||
<SmsLogin
|
||||
disabled={disabled}
|
||||
url={url}
|
||||
callback={callback}
|
||||
/>
|
||||
</div>
|
||||
{loginMode === 'wechatWeb' && <div
|
||||
className={Style['loginbox-qrcode']}
|
||||
>
|
||||
<WeChatLoginQrCode
|
||||
disabled={!!disabled}
|
||||
disableText={disabled}
|
||||
appId={appId}
|
||||
scope="snsapi_login"
|
||||
redirectUri={redirectUri2}
|
||||
state={state}
|
||||
/>
|
||||
</div>}
|
||||
{loginMode === 'wechatPublicForWeb' && <div
|
||||
className={Style['loginbox-qrcode']}
|
||||
>
|
||||
<WechatLoginQrCodeForPublic
|
||||
type="login"
|
||||
oakPath="$login-wechatLogin/qrCode"
|
||||
oakAutoUnmount={true}
|
||||
url={state}
|
||||
/>
|
||||
</div>}
|
||||
{showInput ? (
|
||||
<>
|
||||
<div
|
||||
className={Style['loginbox-password']}
|
||||
style={{
|
||||
display: loginMode === 'password' ? 'block' : 'none',
|
||||
}}
|
||||
>
|
||||
<PasswordLogin
|
||||
disabled={disabled}
|
||||
url={url}
|
||||
callback={callback}
|
||||
/>
|
||||
{Tip}
|
||||
</div>
|
||||
<div
|
||||
className={Style['loginbox-mobile']}
|
||||
style={{
|
||||
display: loginMode === 'sms' ? 'block' : 'none',
|
||||
}}
|
||||
>
|
||||
<SmsLogin
|
||||
disabled={disabled}
|
||||
url={url}
|
||||
callback={callback}
|
||||
/>
|
||||
{Tip}
|
||||
</div>
|
||||
{ScanMethods}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
{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={200}
|
||||
/>
|
||||
{Tip}
|
||||
</div>}
|
||||
{InputMethods}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div >
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ export default OakComponent({
|
|||
properties: {
|
||||
type: 'bind' as EntityDict['wechatLogin']['Schema']['type'],
|
||||
url: '',
|
||||
size: undefined,
|
||||
},
|
||||
methods: {
|
||||
async createWechatLogin() {
|
||||
|
|
|
|||
|
|
@ -16,11 +16,12 @@ export default function Render(
|
|||
loading: boolean;
|
||||
successful: boolean;
|
||||
type: EntityDict['wechatLogin']['Schema']['type'];
|
||||
size: number;
|
||||
},
|
||||
{}
|
||||
>
|
||||
) {
|
||||
const { oakFullpath, qrCodeUrl, loading, successful, type } = props.data;
|
||||
const { oakFullpath, qrCodeUrl, loading, successful, type, size } = props.data;
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
|
@ -31,6 +32,7 @@ export default function Render(
|
|||
tips={<div>微信扫一扫</div>}
|
||||
successful={successful}
|
||||
type={type}
|
||||
size={size}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -319,7 +319,10 @@ const i18ns: I18n[] = [
|
|||
"Mobile": "请输入手机号",
|
||||
"Password": "请输入密码"
|
||||
},
|
||||
"resendAfter": "秒后可重发"
|
||||
"resendAfter": "秒后可重发",
|
||||
"otherMethods": "其他登录方式",
|
||||
"scanLogin": "扫码登录",
|
||||
"tip": "未注册用户首次登录将自动注册"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue