Преглед изворни кода

'添加登录页面注册弹窗基础代码'

main
郑州 пре 3 година
родитељ
комит
9af2161372
4 измењених фајлова са 257 додато и 16 уклоњено
  1. +12
    -0
      src/pages/login/SmsInputer.less
  2. +66
    -0
      src/pages/login/SmsInputer.tsx
  3. +133
    -11
      src/pages/login/index.tsx
  4. +46
    -5
      src/pages/login/login.less

+ 12
- 0
src/pages/login/SmsInputer.less Прегледај датотеку

@@ -0,0 +1,12 @@
.smsInp {
display: flex;
flex-direction: row;
.inp {
flex: 1;
}
.btn {
flex: 0 0 120px;
margin-left: 16px;
// width: 120px;
}
}

+ 66
- 0
src/pages/login/SmsInputer.tsx Прегледај датотеку

@@ -0,0 +1,66 @@
import React, { useState } from 'react';
import { Button, Input, InputProps, message } from 'antd';
import styles from './SmsInputer.less';
import { useCallback } from 'react';
import { throttle } from 'lodash';
import { handleRequest, isValidPhone } from '@/utils/tool';
import { useInterval } from 'ahooks';
import classNames from 'classnames';

interface SmsInputerProps extends InputProps {
phone?: string;
}

export default function SmsInputer(props: SmsInputerProps) {
const { phone, className, ...inpProps } = props;
const [tickFlag, setTickFlag] = useState(false);
const [timeNum, setTimeNum] = useState(59);
// 发送验证码
const sendCodeRequest = useCallback(
throttle(async () => {
if (tickFlag) return;
if (!(phone && isValidPhone(phone))) {
message.error('请先填写正确的手机号');
return;
}
setTickFlag(true);
// todo: 调用发送验证码的接口
const res: API.ResponseData<null> = {
code: 0,
data: null,
requestIsSuccess: true,
success: true,
};
handleRequest(res).error(() => {
message.error('验证码发送失败,请稍后再试');
setTickFlag(false);
});
}),
[phone],
);

useInterval(
() => {
if (timeNum === 0) {
setTickFlag(false);
setTimeNum(59);
return;
}
setTimeNum((v) => v - 1);
},
tickFlag ? 1000 : null,
);

return (
<div className={classNames(styles.smsInp, className)}>
<Input className={styles.inp} {...inpProps} />
<Button
className={styles.btn}
disabled={tickFlag}
onClick={sendCodeRequest}
>
{tickFlag ? `重新获取 ${timeNum}` : '获取验证码'}
</Button>
</div>
);
}

+ 133
- 11
src/pages/login/index.tsx Прегледај датотеку

@@ -1,5 +1,5 @@
import React, { useState } from 'react';
import { Input, Button, Form } from 'antd';
import { Input, Button, Form, Modal, ModalProps } from 'antd';
import styles from './login.less';
import { history, useModel } from 'umi';
import { MobileFilled, LockFilled } from '@ant-design/icons';
@@ -7,13 +7,19 @@ import css from 'classnames';
import { useCallback } from 'react';
import { useEffect } from 'react';
import { login } from '@/services/user';
import { handleRequest } from '@/utils/tool';
import { handleRequest, passwordReg } from '@/utils/tool';
import { useForm } from 'antd/lib/form/Form';
import classNames from 'classnames';
import SmsInputer from './SmsInputer';
import { memoize } from 'lodash';
import { Rule } from 'antd/lib/form';

export default function Login() {
const [errText, setErrText] = useState('');
const [account, setAccount] = useState('');
const [password, setPassword] = useState('');
const [loading, setLoading] = useState(false);
const [regModalVisible, setRegModalVisible] = useState(false);
const { refresh } = useModel('@@initialState');
// const { loading, signin } = useModel('useAuthModel');

@@ -71,16 +77,132 @@ export default function Login() {
onChange={(e) => setPassword(e.target.value)}
/>
<div className={styles.errText}>{errText}</div>
<Button
loading={loading}
type="primary"
block
onClick={onLogin}
htmlType="submit"
>
登录
</Button>
<div className={styles.btnGroup}>
<Button
loading={loading}
type="primary"
className={styles.btn}
onClick={onLogin}
htmlType="submit"
>
登录
</Button>
<Button
className={styles.btn}
onClick={() => setRegModalVisible(true)}
>
注册
</Button>
</div>
</Form>
<RegisterModal
visible={regModalVisible}
onCancel={() => setRegModalVisible(false)}
/>
</div>
);
}

interface RegisterModalProps extends ModalProps {}

const defaultValidateMessages = {
required: '${label}不能为空',
};

const requiredRules: (...arg: Rule[]) => Rule[] = memoize((...otherRules) => [
{ required: true },
...otherRules,
]);

function RegisterModal(props: RegisterModalProps) {
const { className, ...restProps } = props;
const [form] = useForm();
useEffect(() => {
if (props.visible) {
form.resetFields();
}
}, [props.visible, form]);

const onSubmit = useCallback(async () => {
try {
const fields = await form.validateFields();
console.log(fields);
} catch (e) {}
}, [form]);

return (
<Modal
{...restProps}
title="注册企业账户"
width={720}
footer={null}
className={classNames(styles.modal, className)}
maskClosable={false}
>
<Form
form={form}
colon
className={classNames(styles.form)}
labelCol={{ span: 6 }}
validateMessages={defaultValidateMessages}
requiredMark={false}
>
<Form.Item name="companyName" label="公司名称" rules={requiredRules()}>
<Input />
</Form.Item>

<Form.Item name="ccc" label="管理员" rules={requiredRules()}>
<Input />
</Form.Item>

<Form.Item name="phone" label="登录手机号" rules={requiredRules()}>
<Input />
</Form.Item>

<Form.Item
name="password"
label="密码"
rules={requiredRules({
message: '密码8~16位,包含大写字母、小写字母和数字',
pattern: passwordReg,
})}
>
<Input type="password" />
</Form.Item>

<Form.Item
name="confirmPassword"
label="确认密码"
dependencies={['password']}
rules={requiredRules(({ getFieldValue }) => ({
validator(_, value) {
if (!value || getFieldValue('password') === value) {
return Promise.resolve();
}
return Promise.reject(new Error('确认密码和密码不一致'));
},
}))}
>
<Input type="password" />
</Form.Item>

<Form.Item noStyle dependencies={['phone']}>
{() => (
<Form.Item name="sms" label="验证码" rules={requiredRules()}>
<SmsInputer phone={form.getFieldValue('phone')} />
</Form.Item>
)}
</Form.Item>

<Form.Item label=" " className={styles.btnGroup} colon={false}>
<Button className={styles.btn} type="primary" onClick={onSubmit}>
确定
</Button>
<Button className={styles.btn} onClick={props.onCancel}>
取消
</Button>
</Form.Item>
</Form>
</Modal>
);
}

+ 46
- 5
src/pages/login/login.less Прегледај датотеку

@@ -1,6 +1,11 @@
.login {
height: 100%;
background: linear-gradient(270deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.24) 47%, rgba(0, 0, 0, 0.3) 100%);
background: linear-gradient(
270deg,
rgba(0, 0, 0, 0) 0%,
rgba(0, 0, 0, 0.24) 47%,
rgba(0, 0, 0, 0.3) 100%
);
.title {
position: absolute;
left: 60px;
@@ -23,14 +28,50 @@
color: #fff;
margin-bottom: 12px;
&:not(:empty) {
background-color: #D6243A;
background-color: #d6243a;
}
}
.mb24 { margin-bottom: 24px; }
.mb4 { margin-bottom: 4px; }
.mb24 {
margin-bottom: 24px;
}
.mb4 {
margin-bottom: 4px;
}
}
.icon {
color: @primary-color;
font-size: 24px;
}
}
.btnGroup {
display: flex;
flex-direction: row;

.btn {
&:first-child {
flex: 180 180 180px;
}
&:last-child {
flex: 102 102 102px;
margin-left: 8px;
}
}
}
}

.modal {
:global(.ant-modal-body) {
padding: 40px 173px 10px;
}
.btnGroup {
.btn {
border-radius: 8px;
&:first-child {
width: 170px;
}
&:last-child {
margin-left: 20px;
width: 88px;
}
}
}
}

Loading…
Откажи
Сачувај