欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

极客react之Ant Design Pro系列快速入门(二)--登录与默认路径篇

程序员文章站 2024-02-13 16:56:10
...

登录

  1. 在启动篇中加载全局路由时有一句代码如下,方法返回路径和对应的界面

    const routerData = getRouterData(app);

     

  2. 路由配置对象

    const routerConfig = {
         '/': {
         component: dynamicWrapper(app, ['user', 'login'], () => import('../layouts/BasicLayout')),
         },
         
         '/dashboard/analysis': {
         component: dynamicWrapper(app, ['chart'], () => import('../routes/Dashboard/Analysis')),
         },
         '/dashboard/monitor': {
         component: dynamicWrapper(app, ['monitor'], () => import('../routes/Dashboard/Monitor')),
         },
         '/dashboard/workplace': {
         component: dynamicWrapper(app, ['project', 'activities', 'chart'], () =>
             import('../routes/Dashboard/Workplace')
         ),
         // hideInBreadcrumb: true,
         // name: '工作台',
         // authority: 'admin',
         },
         '/test/test': {
         component: dynamicWrapper(app, [], () =>
             import('../routes/test/NormalLoginForm')
         ),
         // hideInBreadcrumb: true,
         // name: '工作台',
         // authority: 'admin',
         },
         '/form/basic-form': {
         component: dynamicWrapper(app, ['form'], () => import('../routes/Forms/BasicForm')),
         },
         '/form/step-form': {
         component: dynamicWrapper(app, ['form'], () => import('../routes/Forms/StepForm')),
         },
         '/form/step-form/info': {
         name: '分步表单(填写转账信息)',
         component: dynamicWrapper(app, ['form'], () => import('../routes/Forms/StepForm/Step1')),
         },
         '/form/step-form/confirm': {
         name: '分步表单(确认转账信息)',
         component: dynamicWrapper(app, ['form'], () => import('../routes/Forms/StepForm/Step2')),
         },
         '/form/step-form/result': {
         name: '分步表单(完成)',
         component: dynamicWrapper(app, ['form'], () => import('../routes/Forms/StepForm/Step3')),
         },
         '/form/advanced-form': {
         component: dynamicWrapper(app, ['form'], () => import('../routes/Forms/AdvancedForm')),
         },
         '/list/table-list': {
         component: dynamicWrapper(app, ['rule'], () => import('../routes/List/TableList')),
         },
         '/list/basic-list': {
         component: dynamicWrapper(app, ['list'], () => import('../routes/List/BasicList')),
         },
         '/list/card-list': {
         component: dynamicWrapper(app, ['list'], () => import('../routes/List/CardList')),
         },
         '/list/search': {
         component: dynamicWrapper(app, ['list'], () => import('../routes/List/List')),
         },
         '/list/search/projects': {
         component: dynamicWrapper(app, ['list'], () => import('../routes/List/Projects')),
         },
         '/list/search/applications': {
         component: dynamicWrapper(app, ['list'], () => import('../routes/List/Applications')),
         },
         '/list/search/articles': {
         component: dynamicWrapper(app, ['list'], () => import('../routes/List/Articles')),
         },
         '/profile/basic': {
         component: dynamicWrapper(app, ['profile'], () => import('../routes/Profile/BasicProfile')),
         },
         '/profile/advanced': {
         component: dynamicWrapper(app, ['profile'], () =>
             import('../routes/Profile/AdvancedProfile')
         ),
         },
         '/result/success': {
         component: dynamicWrapper(app, [], () => import('../routes/Result/Success')),
         },
         '/result/fail': {
         component: dynamicWrapper(app, [], () => import('../routes/Result/Error')),
         },
         '/exception/403': {
         component: dynamicWrapper(app, [], () => import('../routes/Exception/403')),
         },
         '/exception/404': {
         component: dynamicWrapper(app, [], () => import('../routes/Exception/404')),
         },
         '/exception/500': {
         component: dynamicWrapper(app, [], () => import('../routes/Exception/500')),
         },
         '/exception/trigger': {
         component: dynamicWrapper(app, ['error'], () =>
             import('../routes/Exception/triggerException')
         ),
         },
         '/user': {
         component: dynamicWrapper(app, [], () => import('../layouts/UserLayout')),
         },
         '/user/login': {
         component: dynamicWrapper(app, ['login'], () => import('../routes/User/Login')),
         },
         '/user/register': {
         component: dynamicWrapper(app, ['register'], () => import('../routes/User/Register')),
         },
         '/user/register-result': {
         component: dynamicWrapper(app, [], () => import('../routes/User/RegisterResult')),
         },
         // '/user/:id': {
         //   component: dynamicWrapper(app, [], () => import('../routes/User/SomeComponent')),
         // },
     };

     

  3. 根据默认路由/user/login找到对应的登录界面app/src/routes/User/Login.js

    import React, { Component } from 'react';
     import { connect } from 'dva';
     import { Link } from 'dva/router';
     import { Checkbox, Alert, Icon } from 'antd';
     import Login from 'components/Login';
     import styles from './Login.less';
    
     const { Tab, UserName, Password, Mobile, Captcha, Submit } = Login;
     // 此操作符连接命名空间为login的model层
     @connect(({ login, loading }) => ({
     login,
     submitting: loading.effects['login/login'],
     }))
     export default class LoginPage extends Component {
     state = {
         type: 'account',
         autoLogin: true,
     };
    
     onTabChange = type => {
         this.setState({ type });
     };
    
     handleSubmit = (err, values) => {
         const { type } = this.state;
         const { dispatch } = this.props;
         if (!err) {
         // 调用loigin命名空间下的login方法
         dispatch({
             type: 'login/login',
             payload: {
             ...values,
             type,
             },
         });
         }
     };
    
     changeAutoLogin = e => {
         this.setState({
         autoLogin: e.target.checked,
         });
     };
    
     renderMessage = content => {
         return <Alert style={{ marginBottom: 24 }} message={content} type="error" showIcon />;
     };
     // 登录界面,可以更改为自定义的UI
     render() {
         const { login, submitting } = this.props;
         const { type, autoLogin } = this.state;
         return (
         <div className={styles.main}>
             <Login defaultActiveKey={type} onTabChange={this.onTabChange} onSubmit={this.handleSubmit}>
             <Tab key="account" tab="账户密码登录">
                 {login.status === 'error' &&
                 login.type === 'account' &&
                 !submitting &&
                 this.renderMessage('账户或密码错误(admin/888888)')}
                 <UserName name="userName" placeholder="admin/user" />
                 <Password name="password" placeholder="888888/123456" />
             </Tab>
             <Tab key="mobile" tab="手机号登录">
                 {login.status === 'error' &&
                 login.type === 'mobile' &&
                 !submitting &&
                 this.renderMessage('验证码错误')}
                 <Mobile name="mobile" />
                 <Captcha name="captcha" />
             </Tab>
             <div>
                 <Checkbox checked={autoLogin} onChange={this.changeAutoLogin}>
                 自动登录
                 </Checkbox>
                 <a style={{ float: 'right' }} href="">
                 忘记密码
                 </a>
             </div>
             <Submit loading={submitting}>登录</Submit>
             <div className={styles.other}>
                 其他登录方式
                 <Icon className={styles.icon} type="alipay-circle" />
                 <Icon className={styles.icon} type="taobao-circle" />
                 <Icon className={styles.icon} type="weibo-circle" />
                 <Link className={styles.register} to="/user/register">
                 注册账户
                 </Link>
             </div>
             </Login>
         </div>
         );
     }
     }

     

  4. 登录处理

    文件路径:app/src/model/login.js

    import { routerRedux } from 'dva/router';
     import { stringify } from 'qs';
     import { fakeAccountLogin } from '../services/api';
     import { setAuthority } from '../utils/authority';
     import { reloadAuthorized } from '../utils/Authorized';
     import { getPageQuery } from '../utils/utils';
    
     export default {
     namespace: 'login',
    
     state: {
         status: undefined,
     },
    
     effects: {
         *login({ payload }, { call, put }) {
         const response = yield call(fakeAccountLogin, payload);
         yield put({
             type: 'changeLoginStatus',
             payload: response,
         });
         // Login successfully
         if (response.status === 'ok') {
             reloadAuthorized();
             const urlParams = new URL(window.location.href);
             const params = getPageQuery();
             let { redirect } = params;
             if (redirect) {
             const redirectUrlParams = new URL(redirect);
             if (redirectUrlParams.origin === urlParams.origin) {
                 redirect = redirect.substr(urlParams.origin.length);
                 if (redirect.startsWith('/#')) {
                 redirect = redirect.substr(2);
                 }
             } else {
                 window.location.href = redirect;
                 return;
             }
             }
             yield put(routerRedux.replace(redirect || '/'));
         }
         },
         *logout(_, { put }) {
         yield put({
             type: 'changeLoginStatus',
             payload: {
             status: false,
             currentAuthority: 'guest',
             },
         });
         reloadAuthorized();
         yield put(
             routerRedux.push({
             pathname: '/user/login',
             search: stringify({
                 redirect: window.location.href,
             }),
             })
         );
         },
     },
    
     reducers: {
         changeLoginStatus(state, { payload }) {
         setAuthority(payload.currentAuthority);
         return {
             ...state,
             status: payload.status,
             type: payload.type,
         };
         },
     },
     };
    

     

  5. 调用rest接口

    文件目录:app/src/services/api.js

    // 方法名:fakeAccountLogin
     export async function fakeAccountLogin(params) {
     return request('/api/login/account', {
         method: 'POST',
         body: params,
     });
     }

     

  6. 登录默认路径

    ant登录主要是看有没有上次登录地址,如果没有则重定向根目录/,也就是会定向到路由数组的第一个值

    在登录完成处理中的定义返回的首次登录路由,更改如下:

    // Login successfully
       if (response.status === 'ok') {
         reloadAuthorized();
         const urlParams = new URL(window.location.href);
         const params = getPageQuery();
         // gxg 如果是用户登录时返回登录路径,则以用户登录路径为准
         let defaultPath = response.path;
         if(defaultPath){
           yield put(
             routerRedux.push({
               pathname: defaultPath,
               search: stringify({
                 redirect: window.location.href,
               }),
             })
           );
         }else{
           let { redirect } = params;
           if (redirect) {
             const redirectUrlParams = new URL(redirect);
             if (redirectUrlParams.origin === urlParams.origin) {
               redirect = redirect.substr(urlParams.origin.length);
               if (redirect.startsWith('/#')) {
                 redirect = redirect.substr(2);
               }
             } else {
               window.location.href = redirect;
               return;
             }
           }
           // 重定向路径
           yield put(routerRedux.replace(redirect || '/'));
         }
    
       }

    .roadhogrc.mock.js模拟rest api要进行更改

    'POST /api/login/account': (req, res) => {
    const { password, userName, type } = req.body;
    if (password === '888888' && userName === 'admin') {
      res.send({
        status: 'ok',
        type,
        currentAuthority: 'admin',
        path: '/profile/basic',
      });
      return;
    }