授权组件ui调整 mobile绑定手机号
This commit is contained in:
parent
c65043e2c1
commit
56b6132dc2
|
|
@ -1,8 +1,6 @@
|
|||
.oak-loginGrant {
|
||||
&_dev {
|
||||
height: 280px;
|
||||
border: 1px dashed var(--oak-color-primary);
|
||||
padding: 10px;
|
||||
height: 180px;
|
||||
|
||||
&_header {
|
||||
display: flex;
|
||||
|
|
@ -42,31 +40,7 @@
|
|||
box-shadow: 0 2px #00000004;
|
||||
cursor: pointer;
|
||||
transition: .3s;
|
||||
|
||||
|
||||
}
|
||||
|
||||
&_btn:hover {
|
||||
color: var(--oak-color-primary);
|
||||
border-color: currentColor;
|
||||
}
|
||||
|
||||
&_btn::after {
|
||||
/*其他样式*/
|
||||
opacity: 0;
|
||||
box-shadow: 0 0 0 6px var(--oak-color-primary);
|
||||
transition: .3s;
|
||||
}
|
||||
|
||||
/*点击*/
|
||||
&_btn:active::after {
|
||||
box-shadow: none;
|
||||
opacity: 0.4;
|
||||
transition: 0s;
|
||||
/*取消过渡*/
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -93,9 +67,7 @@
|
|||
}
|
||||
|
||||
&_prod {
|
||||
height: 280px;
|
||||
border: 1px dashed var(--oak-color-primary);
|
||||
padding: 10px;
|
||||
height: 180px;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import { message } from 'antd';
|
||||
import { message, Button } from 'antd';
|
||||
import { random, template } from 'oak-domain/lib/utils/string';
|
||||
import classNames from 'classnames';
|
||||
import './index.less';
|
||||
|
|
@ -65,11 +65,14 @@ function Grant(props: GrantProps) {
|
|||
setCode(e.target.value);
|
||||
}}
|
||||
></input>
|
||||
<button
|
||||
className={`${prefixCls2}_dev_header_btn`}
|
||||
<Button
|
||||
type="primary"
|
||||
shape="round"
|
||||
size="large"
|
||||
// block
|
||||
onClick={() => {
|
||||
if (disabled) {
|
||||
messageApi.info(disableText || '禁用');
|
||||
messageApi.info(disableText || 'disabled');
|
||||
return;
|
||||
}
|
||||
window.location.href =
|
||||
|
|
@ -77,13 +80,10 @@ function Grant(props: GrantProps) {
|
|||
`?code=${code}&state=${state}`;
|
||||
}}
|
||||
>
|
||||
微信登录
|
||||
</button>
|
||||
微信授权一键登录
|
||||
</Button>
|
||||
</div>
|
||||
<div className={`${prefixCls2}_dev_bottom`}>
|
||||
<span className={`${prefixCls2}_dev_bottom_title`}>
|
||||
模拟微信授权登录
|
||||
</span>
|
||||
<span className={`${prefixCls2}_dev_bottom_desc`}>
|
||||
1、由于本地开发环境限制,模拟微信授权后动作
|
||||
</span>
|
||||
|
|
@ -98,12 +98,15 @@ function Grant(props: GrantProps) {
|
|||
V = (
|
||||
<div className={`${prefixCls2}_prod`}>
|
||||
<div className={`${prefixCls2}_prod_header`}>
|
||||
<button
|
||||
className={`${prefixCls2}_prod_header_btn`}
|
||||
<Button
|
||||
type="primary"
|
||||
shape="round"
|
||||
size="large"
|
||||
// block
|
||||
onClick={() => {
|
||||
if (disabled) {
|
||||
messageApi.info(disableText || '禁用');
|
||||
return
|
||||
messageApi.info(disableText || 'disabled');
|
||||
return;
|
||||
}
|
||||
const url = WeChatLoginUrl(
|
||||
redirectUri,
|
||||
|
|
@ -115,13 +118,8 @@ function Grant(props: GrantProps) {
|
|||
window.location.href = url;
|
||||
}}
|
||||
>
|
||||
微信登录
|
||||
</button>
|
||||
</div>
|
||||
<div className={`${prefixCls2}_prod_bottom`}>
|
||||
<span className={`${prefixCls2}_prod_bottom_title`}>
|
||||
微信授权登录
|
||||
</span>
|
||||
微信授权一键登录
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"navigationBarTitleText": "手机号登录",
|
||||
"navigationBarTitleText": "绑定手机号",
|
||||
"usingComponents": {
|
||||
"l-button": "../../../miniprogram_npm/lin-ui/button/index"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,9 +25,11 @@ export default OakComponent({
|
|||
if (typeof lastSendAt === 'number') {
|
||||
counter = Math.max(60 - Math.ceil((now - lastSendAt) / 1000), 0);
|
||||
if (counter > 0) {
|
||||
(this as any).counterHandler = setTimeout(() => this.reRender(), 1000);
|
||||
}
|
||||
else if ((this as any).counterHandler) {
|
||||
(this as any).counterHandler = setTimeout(
|
||||
() => this.reRender(),
|
||||
1000
|
||||
);
|
||||
} else if ((this as any).counterHandler) {
|
||||
clearTimeout((this as any).counterHandler);
|
||||
(this as any).counterHandler = undefined;
|
||||
}
|
||||
|
|
@ -37,11 +39,14 @@ export default OakComponent({
|
|||
};
|
||||
},
|
||||
methods: {
|
||||
onInput(e: any) {
|
||||
const { dataset, value } = this.resolveInput(e);
|
||||
const { attr } = dataset;
|
||||
setMobile(value: string) {
|
||||
this.setState({
|
||||
[attr]: value,
|
||||
mobile: value,
|
||||
});
|
||||
},
|
||||
setCaptcha(value: string) {
|
||||
this.setState({
|
||||
captcha: value,
|
||||
});
|
||||
},
|
||||
async sendCaptcha() {
|
||||
|
|
@ -55,8 +60,7 @@ export default OakComponent({
|
|||
});
|
||||
this.save(SEND_KEY, Date.now());
|
||||
this.reRender();
|
||||
}
|
||||
catch (err) {
|
||||
} catch (err) {
|
||||
this.setMessage({
|
||||
type: 'error',
|
||||
content: (err as Error).message,
|
||||
|
|
@ -67,20 +71,22 @@ export default OakComponent({
|
|||
const { eventLoggedIn } = this.props;
|
||||
const { mobile, password, captcha } = this.state;
|
||||
try {
|
||||
await this.features.token.loginByMobile(mobile, password, captcha);
|
||||
await this.features.token.loginByMobile(
|
||||
mobile,
|
||||
password,
|
||||
captcha
|
||||
);
|
||||
if (eventLoggedIn) {
|
||||
this.pub(eventLoggedIn);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
this.navigateBack();
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
} catch (err) {
|
||||
this.setMessage({
|
||||
type: 'error',
|
||||
content: (err as Error).message,
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"Login": "进入",
|
||||
"Login": "确定",
|
||||
"Send": "发送验证码",
|
||||
"placeholder": {
|
||||
"Captcha": "输入4位短信验证码",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,101 @@
|
|||
|
||||
|
||||
.loginbox-main {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
background: var(--oak-bg-color-container);
|
||||
padding-top: 20%;
|
||||
}
|
||||
|
||||
.loginbox-wrap {
|
||||
width: 90%;
|
||||
display: block;
|
||||
background: var(--oak-bg-color-container);
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 4px rgb(0 0 0 / 8%), 0 0 4px rgb(0 0 0 / 8%);
|
||||
}
|
||||
|
||||
.loginbox-hd {
|
||||
padding: 32px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.loginbox-bd {
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
.loginbox-only {
|
||||
padding-top: 32px !important;
|
||||
}
|
||||
|
||||
.loginbox-mobile {
|
||||
position: relative;
|
||||
padding: 0 32px;
|
||||
}
|
||||
|
||||
.loginbox-password {
|
||||
position: relative;
|
||||
padding: 0 32px;
|
||||
}
|
||||
|
||||
.loginbox-qrcode {
|
||||
padding: 0 32px;
|
||||
font-size: 14px;
|
||||
|
||||
&__sociallogin {
|
||||
margin-bottom: 15px;
|
||||
text-align: center;
|
||||
color: #999;
|
||||
|
||||
}
|
||||
|
||||
|
||||
&__refresh {
|
||||
color: var(--oak-text-color-brand);
|
||||
margin-left: 10px;
|
||||
cursor: pointer;
|
||||
|
||||
&-icon {
|
||||
color: var(--oak-text-color-brand)
|
||||
}
|
||||
}
|
||||
|
||||
&__iframe {
|
||||
position: relative;
|
||||
width: 160px;
|
||||
height: 160px;
|
||||
margin: 0 auto;
|
||||
border: #999 solid 1px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.current {
|
||||
color: var(--oak-text-color-brand) !important;
|
||||
cursor: default;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.loginbox-input {
|
||||
.t-input {
|
||||
background-color: rgba(0, 0, 0, .04) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.loginbox-ft {
|
||||
height: 54px;
|
||||
border-top: 1px solid #f2f3f5;
|
||||
font-size: 14px;
|
||||
|
||||
&__btn {}
|
||||
}
|
||||
|
||||
.loginbox-protocal {
|
||||
padding: 20px 32px;
|
||||
}
|
||||
|
|
@ -21,18 +21,8 @@
|
|||
|
||||
.loginbox-hd {
|
||||
padding: 32px;
|
||||
|
||||
&__tab {
|
||||
width: 100%;
|
||||
height: 38px;
|
||||
background-color: rgba(0, 0, 0, .04) !important;
|
||||
}
|
||||
|
||||
&__tabcon {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.loginbox-bd {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,118 @@
|
|||
import React from 'react';
|
||||
import {
|
||||
isMobile,
|
||||
isPassword,
|
||||
isCaptcha,
|
||||
} from 'oak-domain/lib/utils/validator';
|
||||
import { WebComponentProps } from 'oak-frontend-base';
|
||||
import { EntityDict } from '../../../general-app-domain';
|
||||
import { MobileOutlined } from '@ant-design/icons';
|
||||
import { Form, Input, Button } from 'antd';
|
||||
import Style from './web.module.less';
|
||||
|
||||
|
||||
export default function render(
|
||||
props: WebComponentProps<
|
||||
EntityDict,
|
||||
'token',
|
||||
false,
|
||||
{
|
||||
counter: number;
|
||||
loginMode?: number;
|
||||
loginAgreed?: boolean;
|
||||
appId: string;
|
||||
onlyCaptcha?: boolean;
|
||||
onlyPassword?: boolean;
|
||||
loading: boolean;
|
||||
backUrl?: string;
|
||||
mobile: string;
|
||||
captcha: string;
|
||||
},
|
||||
{
|
||||
setCaptcha: (mobile: string) => void;
|
||||
setMobile: (mobile: string) => void;
|
||||
sendCaptcha: () => Promise<void>;
|
||||
loginByMobile: () => Promise<void>;
|
||||
}
|
||||
>
|
||||
) {
|
||||
const { mobile, captcha, counter } = props.data;
|
||||
const { t, setMobile, setCaptcha, sendCaptcha, loginByMobile } =
|
||||
props.methods;
|
||||
const validMobile = isMobile(mobile);
|
||||
const validCaptcha = isCaptcha(captcha);
|
||||
const allowSubmit = validMobile && validCaptcha;
|
||||
|
||||
const LoginCaptcha = (
|
||||
<Form colon={true}>
|
||||
<Form.Item name="mobile">
|
||||
<Input
|
||||
allowClear
|
||||
value={mobile}
|
||||
data-attr="mobile"
|
||||
type="tel"
|
||||
maxLength={11}
|
||||
prefix={<MobileOutlined />}
|
||||
placeholder={t('placeholder.Mobile')}
|
||||
size="large"
|
||||
onChange={(e) => {
|
||||
setMobile(e.target.value);
|
||||
}}
|
||||
className={Style['loginbox-input']}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item name="captcha">
|
||||
<Input
|
||||
allowClear
|
||||
value={captcha}
|
||||
data-attr="captcha"
|
||||
// type="number"
|
||||
maxLength={4}
|
||||
placeholder={t('placeholder.Captcha')}
|
||||
size="large"
|
||||
onChange={(e) => {
|
||||
setCaptcha(e.target.value);
|
||||
}}
|
||||
className={Style['loginbox-input']}
|
||||
suffix={
|
||||
<Button
|
||||
type="link"
|
||||
disabled={!validMobile || counter > 0}
|
||||
onClick={() => sendCaptcha()}
|
||||
>
|
||||
{counter > 0 ? `${counter}秒后可重发` : t('Send')}
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item>
|
||||
<Button
|
||||
block
|
||||
size="large"
|
||||
type="primary"
|
||||
htmlType="submit"
|
||||
disabled={!allowSubmit}
|
||||
onClick={() => loginByMobile()}
|
||||
>
|
||||
{t('Login')}
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={Style['loginbox-main']}>
|
||||
<div className={Style['loginbox-wrap']}>
|
||||
<div className={Style['loginbox-hd']}>
|
||||
为了更好的体验,请绑定手机号
|
||||
</div>
|
||||
<div className={Style['loginbox-bd']}>
|
||||
<div className={Style['loginbox-mobile']}>
|
||||
{LoginCaptcha}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -6,10 +6,9 @@ import {
|
|||
} from 'oak-domain/lib/utils/validator';
|
||||
import { WebComponentProps } from 'oak-frontend-base';
|
||||
import { EntityDict } from '../../../general-app-domain';
|
||||
import { MailOutlined } from '@ant-design/icons';
|
||||
import { Form, Input, Button, Checkbox } from 'antd';
|
||||
import Style from './web.module.less';
|
||||
|
||||
import { MobileOutlined } from '@ant-design/icons';
|
||||
import { Form, Input, Button } from 'antd';
|
||||
import Style from './mobile.module.less';
|
||||
|
||||
export default function render(
|
||||
props: WebComponentProps<
|
||||
|
|
@ -30,15 +29,16 @@ export default function render(
|
|||
password: string;
|
||||
},
|
||||
{
|
||||
sendCaptcha: (mobile: string) => Promise<void>;
|
||||
loginByMobile: (
|
||||
mobile: string,
|
||||
password?: string,
|
||||
captcha?: string
|
||||
) => Promise<void>;
|
||||
setCaptcha: (mobile: string) => void;
|
||||
setMobile: (mobile: string) => void;
|
||||
sendCaptcha: () => Promise<void>;
|
||||
loginByMobile: () => Promise<void>;
|
||||
}
|
||||
>) {
|
||||
/* const { mobile, captcha, password, counter } = props.data;
|
||||
>
|
||||
) {
|
||||
const { mobile, captcha, password, counter } = props.data;
|
||||
const { t, setMobile, setCaptcha, sendCaptcha, loginByMobile } =
|
||||
props.methods;
|
||||
const validMobile = isMobile(mobile);
|
||||
const validCaptcha = isCaptcha(captcha);
|
||||
const allowSubmit = validMobile && validCaptcha;
|
||||
|
|
@ -52,13 +52,11 @@ export default function render(
|
|||
data-attr="mobile"
|
||||
type="tel"
|
||||
maxLength={11}
|
||||
prefix={<MailOutlined />}
|
||||
placeholder={this.t('placeholder.Mobile')}
|
||||
prefix={<MobileOutlined />}
|
||||
placeholder={t('placeholder.Mobile')}
|
||||
size="large"
|
||||
onChange={(e) => {
|
||||
this.setState({
|
||||
mobile: e.target.value,
|
||||
});
|
||||
setMobile(e.target.value);
|
||||
}}
|
||||
className={Style['loginbox-input']}
|
||||
/>
|
||||
|
|
@ -70,23 +68,19 @@ export default function render(
|
|||
data-attr="captcha"
|
||||
// type="number"
|
||||
maxLength={4}
|
||||
placeholder={this.t('placeholder.Captcha')}
|
||||
placeholder={t('placeholder.Captcha')}
|
||||
size="large"
|
||||
onChange={(e) => {
|
||||
this.setState({
|
||||
captcha: e.target.value,
|
||||
});
|
||||
setCaptcha(e.target.value);
|
||||
}}
|
||||
className={Style['loginbox-input']}
|
||||
suffix={
|
||||
<Button
|
||||
type="link"
|
||||
disabled={!validMobile || counter > 0}
|
||||
onClick={() => this.sendCaptcha()}
|
||||
onClick={() => sendCaptcha()}
|
||||
>
|
||||
{counter > 0
|
||||
? `${counter}秒后可重发`
|
||||
: this.t('Send')}
|
||||
{counter > 0 ? `${counter}秒后可重发` : t('Send')}
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
|
|
@ -99,9 +93,9 @@ export default function render(
|
|||
type="primary"
|
||||
htmlType="submit"
|
||||
disabled={!allowSubmit}
|
||||
onClick={() => this.loginByMobile()}
|
||||
onClick={() => loginByMobile()}
|
||||
>
|
||||
{this.t('Login')}
|
||||
{t('Login')}
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
|
|
@ -111,26 +105,14 @@ export default function render(
|
|||
<div className={Style['loginbox-main']}>
|
||||
<div className={Style['loginbox-wrap']}>
|
||||
<div className={Style['loginbox-hd']}>
|
||||
为了更好的体验,请完善账号信息
|
||||
为了更好的体验,请绑定手机号
|
||||
</div>
|
||||
<div className={Style['loginbox-bd']}>
|
||||
<div
|
||||
className={Style['loginbox-mobile']}
|
||||
>
|
||||
<div className={Style['loginbox-mobile']}>
|
||||
{LoginCaptcha}
|
||||
</div>
|
||||
</div>
|
||||
<div className={Style['loginbox-ft']}>
|
||||
<div className={Style['loginbox-ft__btn']}>
|
||||
<div className={Style['loginbox-protocal']}>
|
||||
<Checkbox>
|
||||
<div>阅读并同意 服务条款 和 隐私政策</div>
|
||||
</Checkbox>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
); */
|
||||
return null;
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,25 +8,27 @@ export default OakComponent({
|
|||
mobile: 1,
|
||||
userId: 1,
|
||||
},
|
||||
filters: [{
|
||||
filter() {
|
||||
const token = this.features.token.getToken();
|
||||
return {
|
||||
userId: {
|
||||
$in: {
|
||||
entity: 'token',
|
||||
data: {
|
||||
userId: 1,
|
||||
},
|
||||
filter: {
|
||||
id: token?.id,
|
||||
ableState: 'enabled',
|
||||
filters: [
|
||||
{
|
||||
filter() {
|
||||
const token = this.features.token.getToken();
|
||||
return {
|
||||
userId: {
|
||||
$in: {
|
||||
entity: 'token',
|
||||
data: {
|
||||
userId: 1,
|
||||
},
|
||||
filter: {
|
||||
id: token?.id,
|
||||
ableState: 'enabled',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
},
|
||||
},
|
||||
}],
|
||||
],
|
||||
formData: ({ data: mobiles }) => {
|
||||
return {
|
||||
mobiles,
|
||||
|
|
@ -38,6 +40,9 @@ export default OakComponent({
|
|||
refreshing: false,
|
||||
deleteIdx: undefined,
|
||||
},
|
||||
properties: {
|
||||
showBack: Boolean,
|
||||
},
|
||||
methods: {
|
||||
async onRefreshMobile(e: any) {
|
||||
this.setState({
|
||||
|
|
@ -67,12 +72,11 @@ export default OakComponent({
|
|||
const eventLoggedIn = `mobile:me:login:${Date.now()}`;
|
||||
this.sub(eventLoggedIn, () => {
|
||||
this.navigateBack();
|
||||
})
|
||||
});
|
||||
this.navigateTo({
|
||||
url: '/mobile/login',
|
||||
onlyCaptcha: true,
|
||||
eventLoggedIn,
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
|
||||
.container {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.list {
|
||||
:global {
|
||||
.t-list-item__meta {
|
||||
|
||||
&-avatar {
|
||||
width: auto !important;
|
||||
height: auto !important;
|
||||
background: transparent;
|
||||
border-radius: unset;
|
||||
}
|
||||
&-title {
|
||||
margin: 0 !important;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,25 +1,12 @@
|
|||
|
||||
|
||||
.container {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: var(--oak-bg-color-container);
|
||||
box-shadow: 0 2px 3px #0000001a;
|
||||
border-radius: 3px;
|
||||
padding: 30px 32px;
|
||||
}
|
||||
|
||||
.list {
|
||||
:global {
|
||||
.t-list-item__meta {
|
||||
|
||||
&-avatar {
|
||||
width: auto !important;
|
||||
height: auto !important;
|
||||
background: transparent;
|
||||
border-radius: unset;
|
||||
}
|
||||
&-title {
|
||||
margin: 0 !important;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
margin-top: 10px !important;
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
import React, { useState } from 'react';
|
||||
import { List, Button, Modal } from 'antd';
|
||||
import { MobileOutlined, DeleteOutlined } from '@ant-design/icons';
|
||||
import Style from './web.module.less';
|
||||
import { WebComponentProps } from 'oak-frontend-base';
|
||||
import { EntityDict } from '../../../general-app-domain';
|
||||
import PageHeader from '../../../components/common/pageHeader';
|
||||
|
||||
|
||||
export default function render(
|
||||
props: WebComponentProps<
|
||||
EntityDict,
|
||||
'mobile',
|
||||
true,
|
||||
{
|
||||
mobiles?: EntityDict['mobile']['OpSchema'][];
|
||||
allowRemove: boolean;
|
||||
showBack: boolean;
|
||||
},
|
||||
{
|
||||
goAddMobile: () => void;
|
||||
}
|
||||
>
|
||||
) {
|
||||
const { mobiles, allowRemove, showBack = false } = props.data;
|
||||
const { goAddMobile, removeItem, execute } = props.methods;
|
||||
return (
|
||||
<PageHeader showBack={showBack} title="我的手机号">
|
||||
<div className={Style.container}>
|
||||
<Button type="primary" onClick={() => goAddMobile()}>
|
||||
绑定
|
||||
</Button>
|
||||
<List bordered className={Style.list}>
|
||||
{mobiles?.map((ele, index) => (
|
||||
<List.Item
|
||||
key={index}
|
||||
extra={
|
||||
allowRemove && (
|
||||
<div
|
||||
onClick={() => {
|
||||
const modal = Modal!.confirm!({
|
||||
title: `确认删除吗?删除后无法用此号码登录`,
|
||||
okText: '确定',
|
||||
cancelText: '取消',
|
||||
onOk: async (e) => {
|
||||
removeItem(ele.id);
|
||||
await execute();
|
||||
modal!.destroy!();
|
||||
},
|
||||
onCancel: (e) => {
|
||||
modal!.destroy!();
|
||||
},
|
||||
});
|
||||
}}
|
||||
>
|
||||
<DeleteOutlined />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
>
|
||||
<List.Item.Meta
|
||||
avatar={<MobileOutlined />}
|
||||
title={ele.mobile}
|
||||
></List.Item.Meta>
|
||||
</List.Item>
|
||||
))}
|
||||
</List>
|
||||
</div>
|
||||
</PageHeader>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,18 +1,24 @@
|
|||
import React, { useState } from 'react';
|
||||
import { List, Button, Modal, Dialog } from 'antd-mobile';
|
||||
import { MobileOutlined, DeleteOutlined } from '@ant-design/icons';
|
||||
import Style from './web.module.less';
|
||||
import { WebComponentProps } from 'oak-frontend-base';
|
||||
import { EntityDict } from '../../../general-app-domain';
|
||||
import Style from './mobile.module.less';
|
||||
|
||||
|
||||
|
||||
export default function render(props: WebComponentProps<EntityDict, 'mobile', true, {
|
||||
mobiles?: EntityDict['mobile']['OpSchema'][];
|
||||
allowRemove: boolean;
|
||||
}, {
|
||||
goAddMobile: () => Promise<void>;
|
||||
}>) {
|
||||
export default function render(
|
||||
props: WebComponentProps<
|
||||
EntityDict,
|
||||
'mobile',
|
||||
true,
|
||||
{
|
||||
mobiles?: EntityDict['mobile']['OpSchema'][];
|
||||
allowRemove: boolean;
|
||||
},
|
||||
{
|
||||
goAddMobile: () => void;
|
||||
}
|
||||
>
|
||||
) {
|
||||
const { mobiles, allowRemove } = props.data;
|
||||
const { goAddMobile, removeItem, execute } = props.methods;
|
||||
return (
|
||||
|
|
@ -23,20 +29,22 @@ export default function render(props: WebComponentProps<EntityDict, 'mobile', tr
|
|||
key={index}
|
||||
prefix={<MobileOutlined />}
|
||||
extra={
|
||||
allowRemove && <div
|
||||
onClick={
|
||||
async () => {
|
||||
allowRemove && (
|
||||
<div
|
||||
onClick={async () => {
|
||||
const result = await Dialog.confirm({
|
||||
content: '确认删除吗?删除后无法用此号码登录',
|
||||
})
|
||||
content:
|
||||
'确认删除吗?删除后无法用此号码登录',
|
||||
});
|
||||
if (result) {
|
||||
removeItem(ele.id);
|
||||
await execute();
|
||||
}
|
||||
}}
|
||||
>
|
||||
<DeleteOutlined />
|
||||
</div>
|
||||
>
|
||||
<DeleteOutlined />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
>
|
||||
{ele.mobile}
|
||||
|
|
@ -50,7 +58,7 @@ export default function render(props: WebComponentProps<EntityDict, 'mobile', tr
|
|||
color="primary"
|
||||
onClick={() => goAddMobile()}
|
||||
>
|
||||
添加
|
||||
绑定
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ export default OakComponent({
|
|||
content: '功能开发中',
|
||||
});
|
||||
},
|
||||
setMobile() {
|
||||
goAddMobile() {
|
||||
this.navigateTo({
|
||||
url: '/mobile/me',
|
||||
});
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
<l-list title="生日" data-attr="birth" bind:lintap="setVisibleMp">
|
||||
<view slot="right-section" class="value">{{birthText || '未设置'}}</view>
|
||||
</l-list>
|
||||
<l-list title="手机号" bind:lintap="setMobile">
|
||||
<l-list title="手机号" bind:lintap="goAddMobile">
|
||||
<view slot="right-section" class="value">{{mobile || '未绑定'}}</view>
|
||||
</l-list>
|
||||
<!-- <l-list tag-position="right" is-link="{{false}}" title="用户状态">
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"avatar": "头像",
|
||||
"mobile": "手机号",
|
||||
"manage": "管理",
|
||||
"bind": "绑定"
|
||||
}
|
||||
|
|
@ -7,11 +7,13 @@ import {
|
|||
Radio,
|
||||
DatePicker,
|
||||
Form,
|
||||
Typography,
|
||||
} from 'antd';
|
||||
import dayjs from 'dayjs';
|
||||
import { WebComponentProps } from 'oak-frontend-base';
|
||||
import { EntityDict } from '../../../general-app-domain';
|
||||
import PageHeader from '../../../components/common/pageHeader';
|
||||
import OakAvatar from '../../../components/extraFile/avatar';
|
||||
import Style from './web.module.less';
|
||||
|
||||
|
||||
|
|
@ -33,28 +35,13 @@ export default function Render(
|
|||
genderOptions: Array<{ label: string; value: string }>;
|
||||
},
|
||||
{
|
||||
setMobile: () => void;
|
||||
setAvatar: () => void;
|
||||
setVisible: (visible: boolean, attr: string) => void;
|
||||
setCustomData: (attr: string, value: string | number) => void;
|
||||
onConfirm: (attr: string) => Promise<void>;
|
||||
updateData: (attr: string, value: string | number) => void;
|
||||
updateMyInfo: () => void;
|
||||
goAddMobile: () => void;
|
||||
}
|
||||
>
|
||||
) {
|
||||
const { data, methods } = props;
|
||||
const {
|
||||
t,
|
||||
clean,
|
||||
setAvatar,
|
||||
setVisible,
|
||||
setMobile,
|
||||
setCustomData,
|
||||
onConfirm,
|
||||
updateData,
|
||||
updateMyInfo,
|
||||
} = methods;
|
||||
const { t, updateMyInfo, goAddMobile } = methods;
|
||||
const {
|
||||
nickname,
|
||||
name,
|
||||
|
|
@ -65,6 +52,8 @@ export default function Render(
|
|||
showBack,
|
||||
oakExecuting,
|
||||
genderOptions,
|
||||
oakFullpath,
|
||||
oakDirty,
|
||||
} = data;
|
||||
|
||||
return (
|
||||
|
|
@ -74,6 +63,19 @@ export default function Render(
|
|||
labelCol={{ xs: { span: 4 }, md: { span: 6 } }}
|
||||
wrapperCol={{ xs: { span: 16 }, md: { span: 12 } }}
|
||||
>
|
||||
<Form.Item label={t('avatar')} name="extraFile$entity">
|
||||
<>
|
||||
<OakAvatar
|
||||
oakAutoUnmount={true}
|
||||
oakPath={
|
||||
oakFullpath
|
||||
? oakFullpath + '.extraFile$entity'
|
||||
: undefined
|
||||
}
|
||||
entity="user"
|
||||
/>
|
||||
</>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t('user:attr.name')}
|
||||
name="name"
|
||||
|
|
@ -167,6 +169,21 @@ export default function Render(
|
|||
/>
|
||||
</>
|
||||
</Form.Item>
|
||||
<Form.Item label={t('mobile')}>
|
||||
<>
|
||||
<Space>
|
||||
<Typography>{mobile}</Typography>
|
||||
<Button
|
||||
size="small"
|
||||
onClick={() => {
|
||||
goAddMobile();
|
||||
}}
|
||||
>
|
||||
{mobile ? t('manage') : t('bind')}
|
||||
</Button>
|
||||
</Space>
|
||||
</>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
wrapperCol={{
|
||||
xs: { offset: 4 },
|
||||
|
|
@ -175,7 +192,7 @@ export default function Render(
|
|||
>
|
||||
<Space>
|
||||
<Button
|
||||
disabled={oakExecuting}
|
||||
disabled={oakExecuting || !oakDirty}
|
||||
type="primary"
|
||||
onClick={() => {
|
||||
updateMyInfo();
|
||||
|
|
|
|||
|
|
@ -14,11 +14,10 @@ import type { DatePickerRef } from 'antd-mobile/es/components/date-picker';
|
|||
import dayjs from 'dayjs';
|
||||
import { WebComponentProps } from 'oak-frontend-base';
|
||||
import { EntityDict } from '../../../general-app-domain';
|
||||
import OakGallery from '../../../components/extraFile/gallery';
|
||||
import OakAvatar from '../../../components/extraFile/avatar';
|
||||
import Style from './mobile.module.less';
|
||||
|
||||
|
||||
|
||||
//todo 头像跟绑定手机号 未实现
|
||||
|
||||
type DataProps = {
|
||||
|
|
@ -32,10 +31,11 @@ type DataProps = {
|
|||
attr: string;
|
||||
genderOptions: Array<{ label: string; value: string }>;
|
||||
attrs: Record<string, string>;
|
||||
id: string;
|
||||
};
|
||||
|
||||
type MethodsProps = {
|
||||
setMobile: () => void;
|
||||
goAddMobile: () => void;
|
||||
setAvatar: () => void;
|
||||
setVisible: (visible: boolean, attr: string) => void;
|
||||
setCustomData: (attr: string, value: string | number) => void;
|
||||
|
|
@ -46,26 +46,39 @@ export default function render(
|
|||
props: WebComponentProps<EntityDict, 'user', false, DataProps, MethodsProps>
|
||||
) {
|
||||
const { data, methods } = props;
|
||||
const { t, clean, setAvatar, setVisible, setMobile } = methods;
|
||||
const { visible, nickname, name, birth, gender, mobile, avatarUrl, attr } =
|
||||
data;
|
||||
const { t, clean, setAvatar, setVisible, goAddMobile } = methods;
|
||||
const {
|
||||
oakFullpath,
|
||||
visible,
|
||||
nickname,
|
||||
name,
|
||||
birth,
|
||||
gender,
|
||||
mobile,
|
||||
avatarUrl,
|
||||
attr,
|
||||
id,
|
||||
} = data;
|
||||
|
||||
return (
|
||||
<div className={Style.container}>
|
||||
<div className={Style.avatar_container}>
|
||||
<Avatar
|
||||
src={avatarUrl}
|
||||
className={Style.avatar}
|
||||
/>
|
||||
<Button
|
||||
size='mini'
|
||||
color='primary'
|
||||
onClick={setAvatar}
|
||||
>
|
||||
更新
|
||||
</Button>
|
||||
</div>
|
||||
<List className={Style.list}>
|
||||
<List.Item
|
||||
extra={
|
||||
<OakAvatar
|
||||
oakAutoUnmount={true}
|
||||
oakPath={
|
||||
oakFullpath
|
||||
? oakFullpath + '.extraFile$entity'
|
||||
: undefined
|
||||
}
|
||||
entity="user"
|
||||
entityId={id}
|
||||
/>
|
||||
}
|
||||
>
|
||||
头像
|
||||
</List.Item>
|
||||
<List.Item
|
||||
extra={nickname ? nickname : '未设置'}
|
||||
onClick={() => {
|
||||
|
|
@ -93,10 +106,10 @@ export default function render(
|
|||
<List.Item
|
||||
extra={mobile ? mobile : '未设置'}
|
||||
onClick={() => {
|
||||
setMobile();
|
||||
goAddMobile();
|
||||
}}
|
||||
>
|
||||
手机号
|
||||
{t('mobile')}
|
||||
</List.Item>
|
||||
</List>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue