登录修改

This commit is contained in:
lxy 2024-08-07 17:50:51 +08:00
parent a39d4e2311
commit 8a258d55d4
20 changed files with 475 additions and 216 deletions

View File

@ -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;

View File

@ -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,

View File

@ -10,5 +10,8 @@
"Mobile": "请输入手机号",
"Password": "请输入密码"
},
"resendAfter": "秒后可重发"
"resendAfter": "秒后可重发",
"otherMethods": "其他登录方式",
"scanLogin": "扫码登录",
"tip": "未注册用户首次登录将自动注册"
}

View File

@ -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;

View File

@ -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>);

View File

@ -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;
}
}

View File

@ -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;

View File

@ -28,6 +28,7 @@ export default OakComponent({
properties: {
type: 'bind',
url: '',
size: undefined,
},
methods: {
async createWechatLogin() {

View File

@ -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;

View File

@ -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>);
}

View File

@ -317,7 +317,10 @@ const i18ns = [
"Mobile": "请输入手机号",
"Password": "请输入密码"
},
"resendAfter": "秒后可重发"
"resendAfter": "秒后可重发",
"otherMethods": "其他登录方式",
"scanLogin": "扫码登录",
"tip": "未注册用户首次登录将自动注册"
}
},
{

View File

@ -319,7 +319,10 @@ const i18ns = [
"Mobile": "请输入手机号",
"Password": "请输入密码"
},
"resendAfter": "秒后可重发"
"resendAfter": "秒后可重发",
"otherMethods": "其他登录方式",
"scanLogin": "扫码登录",
"tip": "未注册用户首次登录将自动注册"
}
},
{

View File

@ -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;

View File

@ -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,

View File

@ -10,5 +10,8 @@
"Mobile": "请输入手机号",
"Password": "请输入密码"
},
"resendAfter": "秒后可重发"
}
"resendAfter": "秒后可重发",
"otherMethods": "其他登录方式",
"scanLogin": "扫码登录",
"tip": "未注册用户首次登录将自动注册"
}

View File

@ -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;
}
}

View File

@ -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 >
);
}

View File

@ -31,6 +31,7 @@ export default OakComponent({
properties: {
type: 'bind' as EntityDict['wechatLogin']['Schema']['type'],
url: '',
size: undefined,
},
methods: {
async createWechatLogin() {

View File

@ -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>
);

View File

@ -319,7 +319,10 @@ const i18ns: I18n[] = [
"Mobile": "请输入手机号",
"Password": "请输入密码"
},
"resendAfter": "秒后可重发"
"resendAfter": "秒后可重发",
"otherMethods": "其他登录方式",
"scanLogin": "扫码登录",
"tip": "未注册用户首次登录将自动注册"
}
},
{