login组件 支持url传入,登录之后要返回url页面

This commit is contained in:
wkj 2024-05-22 15:07:48 +08:00
parent f973e923ba
commit 7661f5e13d
16 changed files with 122 additions and 81 deletions

View File

@ -11,7 +11,7 @@ type IQrCodeProps = {
url: string;
loading?: boolean;
disableDownload?: boolean;
successed?: boolean;
successful?: boolean;
type?: EntityDict['wechatLogin']['Schema']['type'];
};
declare function QrCode(props: IQrCodeProps): React.JSX.Element;

View File

@ -9,7 +9,7 @@ function isBase64(url) {
return /data:image\/[\w|\W]+(;base64,)[\w|\W]*/.test(url);
}
function QrCode(props) {
const { filename = 'qrCode.png', expiresAt, tips, onDownload, onRefresh, size = 280, url, loading = false, disableDownload = false, successed, type, } = props;
const { filename = 'qrCode.png', expiresAt, tips, onDownload, onRefresh, size = 280, url, loading = false, disableDownload = false, successful, type, } = props;
const prefixCls = 'oak';
const features = useFeatures();
let V;
@ -40,9 +40,11 @@ function QrCode(props) {
}
}
}
if (successed) {
if (successful) {
return (<div className={`${prefixCls}-qrCodeBox`}>
<Result status="success" title={type === 'bind' ? features.locales.t('weChat-account-successfully-bound') : features.locales.t('weChat-authorization-login-successful')}/>
<Result status="success" title={type === 'bind'
? features.locales.t('weChat-account-successfully-bound')
: features.locales.t('weChat-authorization-login-successful')}/>
</div>);
}
return (<div id="oakQrCode" className={`${prefixCls}-qrCodeBox`}>

View File

@ -3,7 +3,7 @@ import { random } from 'oak-domain/lib/utils/string';
import classNames from 'classnames';
import './index.less';
function QrCode(props) {
const { id = 'login_qr_container', appId, scope, redirectUri, state, style = '', href = '', dev = process.env.NODE_ENV === 'development', // 默认本地为true 发布时为false
const { id = 'login_qr_container', appId, scope, redirectUri, state, style = '', href = "data:text/css;base64,LmltcG93ZXJCb3ggLnFyY29kZSB7d2lkdGg6IDIwMHB4O30KLmltcG93ZXJCb3ggLnRpdGxlIHtkaXNwbGF5OiBub25lO30KLmltcG93ZXJCb3ggLmluZm8ge3dpZHRoOiAyMDBweDt9Ci5zdGF0dXNfaWNvbiB7ZGlzcGxheTogbm9uZX0KLmltcG93ZXJCb3ggLnN0YXR1cyB7dGV4dC1hbGlnbjogY2VudGVyO30gCg==", dev = process.env.NODE_ENV === 'development', // 默认本地为true 发布时为false
disabled = false, disableText, rootStyle, rootClassName, } = props;
const [code, setCode] = useState('');
useEffect(() => {

View File

@ -3,5 +3,7 @@ declare const _default: (props: import("oak-frontend-base").ReactComponentProps<
onlyPassword: boolean;
disabled: string;
redirectUri: string;
url: string;
callback: (() => void) | undefined;
}>) => React.ReactElement;
export default _default;

View File

@ -21,14 +21,16 @@ export default OakComponent({
lastSendAt: undefined,
isSupportWechat: false,
isSupportWechatPublic: false,
isSupportGrant: false,
isSupportWechatGrant: false,
domain: undefined,
},
properties: {
onlyCaptcha: false,
onlyPassword: false,
disabled: '',
redirectUri: '', // 微信登录后的redirectUri要指向wechatUser/login去处理
redirectUri: '',
url: '',
callback: undefined, // 登录成功回调,排除微信登录方式
},
formData({ features, props }) {
const { lastSendAt } = this.state;
@ -51,21 +53,20 @@ export default OakComponent({
lifetimes: {
async ready() {
const application = this.features.application.getApplication();
let loginMode = await this.load(LOGIN_MODE) || 2;
let loginMode = (await this.load(LOGIN_MODE)) || 2;
const lastSendAt = await this.load(SEND_KEY);
const appType = application?.type;
const config = application?.config;
let appId;
let domain; //网站扫码 授权回调域
let isSupportScan = false; //是否支持微信扫码登录
let domain; //网站扫码授权回调域
let isSupportWechat = false; // 微信扫码网站登录
let isSupportWechatPublic = false; // 微信扫码公众号登录
let isSupportGrant = false; // 是否支持微信公众号授权登录
let isSupportWechatGrant = false; // 微信公众号授权登录
if (appType === 'wechatPublic') {
const config2 = config;
const isService = config2?.isService; //是否服务号 服务号才能授权登录
appId = config2?.appId;
isSupportGrant = !!(isService && appId);
isSupportWechatGrant = !!(isService && appId);
isSupportWechat = !!config2?.passport?.includes('wechat');
isSupportWechatPublic = !!config2?.passport?.includes('wechatPublic'); //是否开启
}
@ -76,7 +77,7 @@ export default OakComponent({
isSupportWechat = !!config2?.passport?.includes('wechat');
isSupportWechatPublic = !!config2?.passport?.includes('wechatPublic'); //是否开启
}
if (isSupportGrant) {
if (isSupportWechatGrant) {
loginMode = 1;
}
else if (this.props.onlyPassword) {
@ -86,6 +87,7 @@ export default OakComponent({
loginMode = 2;
}
else {
const isSupportScan = isSupportWechat || isSupportWechatPublic;
loginMode = loginMode === 3 && !isSupportScan ? 2 : loginMode;
}
this.setState({
@ -94,10 +96,10 @@ export default OakComponent({
lastSendAt,
isSupportWechat,
isSupportWechatPublic,
isSupportGrant,
isSupportWechatGrant,
domain,
}, () => this.reRender());
}
},
},
methods: {
async sendCaptcha(mobile) {
@ -122,6 +124,7 @@ export default OakComponent({
}
},
async loginByMobile(mobile, password, captcha) {
const { url, callback } = this.props;
try {
this.setState({
loading: true,
@ -130,6 +133,16 @@ export default OakComponent({
this.setState({
loading: false,
});
if (callback) {
callback();
return;
}
if (url) {
this.redirectTo({
url,
});
return;
}
}
catch (err) {
this.setState({

View File

@ -11,7 +11,7 @@ export default function Render(props: WebComponentProps<EntityDict, 'token', fal
width: string;
isSupportWechat: boolean;
isSupportWechatPublic: boolean;
isSupportGrant: boolean;
isSupportWechatGrant: boolean;
domain?: string;
disabled?: string;
redirectUri: string;

View File

@ -11,7 +11,7 @@ import WechatLoginQrCodeForPublic from '../../wechatLogin/qrCode';
import WeChatLoginGrant from '../../common/weChatLoginGrant';
export default function Render(props) {
const { data, methods } = props;
const { onlyCaptcha, onlyPassword, width, counter, loading, loginMode, appId, domain, isSupportWechat, isSupportWechatPublic, isSupportGrant, disabled, redirectUri, url, } = data;
const { onlyCaptcha, onlyPassword, width, counter, loading, loginMode, appId, domain, isSupportWechat, isSupportWechatPublic, isSupportWechatGrant, disabled, redirectUri, url, } = data;
const { sendCaptcha, loginByMobile, t, setLoginMode } = methods;
const [mobile, setMobile] = useState('');
const [captcha, setCaptcha] = useState('');
@ -65,7 +65,7 @@ export default function Render(props) {
const [options, setOptions] = useState([]);
const getOptions = () => {
const newOptions = [];
if (isSupportGrant) {
if (isSupportWechatGrant) {
newOptions.push({
label: 'WeChatLoginByGrant',
value: 1,
@ -107,13 +107,13 @@ export default function Render(props) {
useEffect(() => {
getOptions();
}, [
isSupportGrant,
isSupportWechatGrant,
onlyPassword,
onlyCaptcha,
isSupportWechat,
isSupportWechatPublic,
]);
// 构建微信扫码所需state参数url存在扫码后重定向url否则返回上一页
// 构建微信扫码所需state参数url存在扫码后重定向url否则返回上一页
let state = '';
if (url) {
state = encodeURIComponent(decodeURIComponent(url));
@ -129,9 +129,9 @@ export default function Render(props) {
</div>)}
<div className={classNames(Style['loginbox-bd'], {
[Style['loginbox-bd__grant']]: isSupportGrant,
[Style['loginbox-bd__grant']]: isSupportWechatGrant,
})}>
{isSupportGrant ? (<div className={Style['loginbox-grant']}>
{isSupportWechatGrant ? (<div className={Style['loginbox-grant']}>
<WeChatLoginGrant disabled={!!disabled} disableText={disabled} appId={appId} scope="snsapi_userinfo" redirectUri={redirectUri} state={state}/>
</div>) : (<>
<div className={Style['loginbox-password']} style={{
@ -147,9 +147,8 @@ export default function Render(props) {
<div className={Style['loginbox-qrcode']} style={{
display: loginMode === 3 ? 'block' : 'none',
}}>
{/*
所以这里可以按这个判断分开显示 */}
{isSupportWechat && (<WeChatLoginQrCode disabled={disabled} disableText={disabled} appId={appId} scope="snsapi_login" redirectUri={redirectUri} state={state} href="data:text/css;base64,LmltcG93ZXJCb3ggLnFyY29kZSB7d2lkdGg6IDIwMHB4O30KLmltcG93ZXJCb3ggLnRpdGxlIHtkaXNwbGF5OiBub25lO30KLmltcG93ZXJCb3ggLmluZm8ge3dpZHRoOiAyMDBweDt9Ci5zdGF0dXNfaWNvbiB7ZGlzcGxheTogbm9uZX0KLmltcG93ZXJCb3ggLnN0YXR1cyB7dGV4dC1hbGlnbjogY2VudGVyO30gCg=="/>)}
{/* 因为在选择授权方式时,微信网站和微信公众号授权登录二者只存其一,所以这里可以按这个判断分开显示 */}
{isSupportWechat && (<WeChatLoginQrCode disabled={!!disabled} disableText={disabled} appId={appId} scope="snsapi_login" redirectUri={redirectUri} state={state}/>)}
{isSupportWechatPublic && (<WechatLoginQrCodeForPublic type="login" oakPath="$login-wechatLogin/qrCode" oakAutoUnmount={true} url={state}/>)}
</div>
</>)}

View File

@ -3,7 +3,6 @@ export default OakComponent({
isList: false,
lifetimes: {
async attached() {
const { type } = this.props;
this.createWechatLogin();
this.createTimer = setInterval(() => {
this.createWechatLogin();
@ -24,7 +23,7 @@ export default OakComponent({
data: {
intervalId: '',
loading: false,
successed: false,
successful: false,
},
properties: {
type: 'bind',
@ -133,7 +132,7 @@ export default OakComponent({
});
const { successed, type } = wechatLogin;
this.setState({
successed,
successful: successed,
type,
}, async () => {
// 未登录的情况下才走这里

View File

@ -5,6 +5,6 @@ export default function Render(props: WebComponentProps<EntityDict, 'wechatLogin
wechatLoginId: string;
qrCodeUrl: string;
loading: boolean;
successed: boolean;
successful: boolean;
type: EntityDict['wechatLogin']['Schema']['type'];
}, {}>): 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, successed, type } = props.data;
const { oakFullpath, qrCodeUrl, loading, successful, type } = props.data;
return (<div>
<QrCode loading={loading} url={qrCodeUrl} disableDownload={true} tips={<div>微信扫一扫</div>} successed={successed} type={type}/>
<QrCode loading={loading} url={qrCodeUrl} disableDownload={true} tips={<div>微信扫一扫</div>} successful={successful} type={type}/>
</div>);
}

View File

@ -18,7 +18,7 @@ type IQrCodeProps = {
url: string;
loading?: boolean;
disableDownload?: boolean;
successed?: boolean;
successful?: boolean;
type?: EntityDict['wechatLogin']['Schema']['type'];
};
@ -38,7 +38,7 @@ function QrCode(props: IQrCodeProps) {
url,
loading = false,
disableDownload = false,
successed,
successful,
type,
} = props;
const prefixCls = 'oak';
@ -79,15 +79,23 @@ function QrCode(props: IQrCodeProps) {
}
}
if (successed) {
if (successful) {
return (
<div className={`${prefixCls}-qrCodeBox`}>
<Result
status="success"
title={type === 'bind' ? features.locales.t('weChat-account-successfully-bound') : features.locales.t('weChat-authorization-login-successful')}
title={
type === 'bind'
? features.locales.t(
'weChat-account-successfully-bound'
)
: features.locales.t(
'weChat-authorization-login-successful'
)
}
/>
</div>
)
);
}
return (

View File

@ -26,7 +26,7 @@ function QrCode(props: QrCodeProps) {
redirectUri,
state,
style = '',
href = '',
href = "data:text/css;base64,LmltcG93ZXJCb3ggLnFyY29kZSB7d2lkdGg6IDIwMHB4O30KLmltcG93ZXJCb3ggLnRpdGxlIHtkaXNwbGF5OiBub25lO30KLmltcG93ZXJCb3ggLmluZm8ge3dpZHRoOiAyMDBweDt9Ci5zdGF0dXNfaWNvbiB7ZGlzcGxheTogbm9uZX0KLmltcG93ZXJCb3ggLnN0YXR1cyB7dGV4dC1hbGlnbjogY2VudGVyO30gCg==",
dev = process.env.NODE_ENV === 'development', // 默认本地为true 发布时为false
disabled = false,
disableText,

View File

@ -24,14 +24,16 @@ export default OakComponent({
lastSendAt: undefined as undefined | number,
isSupportWechat: false,
isSupportWechatPublic: false,
isSupportGrant: false,
isSupportWechatGrant: false,
domain: undefined as string | undefined,
},
properties: {
onlyCaptcha: false,
onlyPassword: false,
disabled: '',
redirectUri: '', // 微信登录后的redirectUri要指向wechatUser/login去处理
redirectUri: '', // 微信登录后的redirectUri要指向wechatUser/login去处理
url: '', // 登录系统之后要返回的页面
callback: undefined as (() => void) | undefined, // 登录成功回调,排除微信登录方式
},
formData({ features, props }) {
const { lastSendAt } = this.state;
@ -61,57 +63,63 @@ export default OakComponent({
async ready() {
const application = this.features.application.getApplication();
let loginMode = await this.load(LOGIN_MODE) || 2;
let loginMode = (await this.load(LOGIN_MODE)) || 2;
const lastSendAt = await this.load(SEND_KEY);
const appType = application?.type as AppType;
const config = application?.config;
let appId;
let domain; //网站扫码 授权回调域
let isSupportScan = false; //是否支持微信扫码登录
let domain; //网站扫码授权回调域
let isSupportWechat = false; // 微信扫码网站登录
let isSupportWechatPublic = false; // 微信扫码公众号登录
let isSupportGrant = false; // 是否支持微信公众号授权登录
let isSupportWechatGrant = false; // 微信公众号授权登录
if (appType === 'wechatPublic') {
const config2 = config as WechatPublicConfig;
const isService = config2?.isService; //是否服务号 服务号才能授权登录
appId = config2?.appId;
isSupportGrant = !!(isService && appId);
isSupportWechatGrant = !!(isService && appId);
isSupportWechat = !!config2?.passport?.includes('wechat');
isSupportWechatPublic = !!config2?.passport?.includes('wechatPublic') //是否开启
isSupportWechatPublic = !!config2?.passport?.includes('wechatPublic'); //是否开启
} else if (appType === 'web') {
const config2 = config as WebConfig;
appId = config2?.wechat?.appId;
domain = config2?.wechat?.domain;
isSupportWechat = !!config2?.passport?.includes('wechat');
isSupportWechatPublic = !!config2?.passport?.includes('wechatPublic') //是否开启
isSupportWechatPublic = !!config2?.passport?.includes('wechatPublic'); //是否开启
}
if (isSupportGrant) {
if (isSupportWechatGrant) {
loginMode = 1;
} else if (this.props.onlyPassword) {
loginMode = 1;
} else if (this.props.onlyCaptcha) {
loginMode = 2;
} else {
const isSupportScan = isSupportWechat || isSupportWechatPublic;
loginMode = loginMode === 3 && !isSupportScan ? 2 : loginMode;
}
this.setState({
loginMode,
appId,
lastSendAt,
isSupportWechat,
isSupportWechatPublic,
isSupportGrant,
domain,
}, () => this.reRender());
}
this.setState(
{
loginMode,
appId,
lastSendAt,
isSupportWechat,
isSupportWechatPublic,
isSupportWechatGrant,
domain,
},
() => this.reRender()
);
},
},
methods: {
async sendCaptcha(mobile: string) {
try {
const result = await this.features.token.sendCaptcha(mobile, 'login');
const result = await this.features.token.sendCaptcha(
mobile,
'login'
);
// 显示返回消息
this.setMessage({
type: 'success',
@ -119,9 +127,12 @@ export default OakComponent({
});
const lastSendAt = Date.now();
await this.save(SEND_KEY, lastSendAt);
this.setState({
lastSendAt,
}, () => this.reRender());
this.setState(
{
lastSendAt,
},
() => this.reRender()
);
} catch (err) {
this.setMessage({
type: 'error',
@ -134,6 +145,7 @@ export default OakComponent({
password?: string,
captcha?: string
) {
const { url, callback } = this.props;
try {
this.setState({
loading: true,
@ -141,11 +153,21 @@ export default OakComponent({
await this.features.token.loginByMobile(
mobile,
password,
captcha,
captcha
);
this.setState({
loading: false,
});
if (callback) {
callback();
return;
}
if (url) {
this.redirectTo({
url,
});
return;
}
} catch (err) {
this.setState({
loading: false,

View File

@ -40,7 +40,7 @@ export default function Render(
width: string;
isSupportWechat: boolean;
isSupportWechatPublic: boolean;
isSupportGrant: boolean;
isSupportWechatGrant: boolean;
domain?: string;
disabled?: string;
redirectUri: string;
@ -69,7 +69,7 @@ export default function Render(
domain,
isSupportWechat,
isSupportWechatPublic,
isSupportGrant,
isSupportWechatGrant,
disabled,
redirectUri,
url,
@ -195,7 +195,7 @@ export default function Render(
const getOptions = () => {
const newOptions: Option[] = [];
if (isSupportGrant) {
if (isSupportWechatGrant) {
newOptions.push({
label: 'WeChatLoginByGrant',
value: 1,
@ -236,14 +236,14 @@ export default function Render(
useEffect(() => {
getOptions();
}, [
isSupportGrant,
isSupportWechatGrant,
onlyPassword,
onlyCaptcha,
isSupportWechat,
isSupportWechatPublic,
]);
// 构建微信扫码所需state参数url存在扫码后重定向url否则返回上一页
// 构建微信扫码所需state参数url存在扫码后重定向url否则返回上一页
let state = '';
if (url) {
state = encodeURIComponent(decodeURIComponent(url));
@ -272,10 +272,10 @@ export default function Render(
<div
className={classNames(Style['loginbox-bd'], {
[Style['loginbox-bd__grant']]: isSupportGrant,
[Style['loginbox-bd__grant']]: isSupportWechatGrant,
})}
>
{isSupportGrant ? (
{isSupportWechatGrant ? (
<div className={Style['loginbox-grant']}>
<WeChatLoginGrant
disabled={!!disabled}
@ -310,17 +310,15 @@ export default function Render(
display: loginMode === 3 ? 'block' : 'none',
}}
>
{/*
*/}
{/* 因为在选择授权方式时,微信网站和微信公众号授权登录二者只存其一,所以这里可以按这个判断分开显示 */}
{isSupportWechat && (
<WeChatLoginQrCode
disabled={disabled}
disabled={!!disabled}
disableText={disabled}
appId={appId}
scope="snsapi_login"
redirectUri={redirectUri}
state={state}
href="data:text/css;base64,LmltcG93ZXJCb3ggLnFyY29kZSB7d2lkdGg6IDIwMHB4O30KLmltcG93ZXJCb3ggLnRpdGxlIHtkaXNwbGF5OiBub25lO30KLmltcG93ZXJCb3ggLmluZm8ge3dpZHRoOiAyMDBweDt9Ci5zdGF0dXNfaWNvbiB7ZGlzcGxheTogbm9uZX0KLmltcG93ZXJCb3ggLnN0YXR1cyB7dGV4dC1hbGlnbjogY2VudGVyO30gCg=="
/>
)}
{isSupportWechatPublic && (

View File

@ -1,5 +1,4 @@
import { EntityDict } from '../../../oak-app-domain';
import { generateNewIdAsync } from 'oak-domain/lib/utils/uuid';
const Interval = 2 * 60 * 1000;
@ -7,7 +6,6 @@ export default OakComponent({
isList: false,
lifetimes: {
async attached() {
const { type } = this.props;
this.createWechatLogin();
(this as any).createTimer = setInterval(() => {
this.createWechatLogin();
@ -28,7 +26,7 @@ export default OakComponent({
data: {
intervalId: '',
loading: false,
successed: false,
successful: false,
},
properties: {
type: 'bind' as EntityDict['wechatLogin']['Schema']['type'],
@ -150,7 +148,7 @@ export default OakComponent({
const { successed, type } = wechatLogin;
this.setState(
{
successed,
successful: successed,
type,
},
async () => {

View File

@ -14,13 +14,13 @@ export default function Render(
wechatLoginId: string;
qrCodeUrl: string;
loading: boolean;
successed: boolean;
type: EntityDict['wechatLogin']['Schema']['type']
successful: boolean;
type: EntityDict['wechatLogin']['Schema']['type'];
},
{}
>
) {
const { oakFullpath, qrCodeUrl, loading, successed, type } = props.data;
const { oakFullpath, qrCodeUrl, loading, successful, type } = props.data;
return (
<div>
@ -29,7 +29,7 @@ export default function Render(
url={qrCodeUrl}
disableDownload={true}
tips={<div></div>}
successed={successed}
successful={successful}
type={type}
/>
</div>