Ant design Pro V5 +Typescript + Hooks + Umi + Dev + SpringBoot + mysql + redis + scrity 实现动态菜单权限管理

2023-11-19

Ant design Pro V5 +Typescript + Hooks + Umi + Dev + SpringBoot + mysql + redis + scrity 实现动态菜单权限管理(企业中台架构)

1,app.tsx页面配置

该页面集成了登陆权限控制,动态菜单渲染,数据的缓存

import type { BasicLayoutProps, Settings as LayoutSettings } from '@ant-design/pro-layout';
import { PageLoading } from '@ant-design/pro-layout';
import { notification } from 'antd';
import type { RequestConfig, RunTimeLayoutConfig } from 'umi';
import { history, Link } from 'umi';
import RightContent from '@/components/RightContent';
import Footer from '@/components/Footer';
//import { currentUser as queryCurrentUser } from './services/ant-design-pro/api';
// import { ApiFilled, BookOutlined, LinkOutlined } from '@ant-design/icons';
import {userCurrentUser as queryCurrentUser} from './services/user-login/userLogin'
import {userMenuList} from './services/user-menu/userMenu'
import type {MenuDataItem} from '@ant-design/pro-layout'
// import { currentUser } from './services/ant-design-pro/api';
const isDev = process.env.NODE_ENV === 'development';
const loginPath = '/user/login';

/** 获取用户信息比较慢的时候会展示一个 loading */
export const initialStateConfig = {
  loading: <PageLoading />,
};

/**
 * @see  https://umijs.org/zh-CN/plugins/plugin-initial-state
 * */
export async function getInitialState(): Promise<{
  settings?: Partial<LayoutSettings>;
  menuData:MenuDataItem[];
  currentUser?: API.CurrentUser;
  fetchUserInfo?: (params:any) => Promise<API.CurrentUser | undefined>;
}> {

  // user onclick login
  const fetchUserInfo = async (params:any) => {
    try {
      const msg = await queryCurrentUser({userName:params.username,passWord:params.password});
      if(msg.data){
        console.log("msg.data----------------------------app.tsx-----------------------------------------------")
        console.log(msg)
        localStorage.setItem("userinfo",JSON.stringify(msg.data));
        const menuData = await userMenuList();
        console.log(menuData)
        localStorage.setItem("menuDataList",JSON.stringify(menuData))
      }
      return msg.data;
    } 
    catch (error) {
      history.push(loginPath);
    }
    return undefined;
  };


  //page show
  // 如果是登录页面,不执行
  if (history.location.pathname !== loginPath) {
    
    // filter 

    //get 
    let menuData = JSON.parse(localStorage.getItem("menuDataList"))
    let currentUser = JSON.parse(localStorage.getItem("userinfo")) || {}
    
    //const userList = await fetchUserInfo();
    console.log("userList-------------------------------")
    //console.log(userList)

    return {
      fetchUserInfo,
      currentUser,
      menuData,
      settings: {},
    };
  }

  console.log("app.tsx--执行------------------------------------------")

  return {
    fetchUserInfo,
    menuData:[],
    settings: {},
  };
}


// ProLayout 支持的api https://procomponents.ant.design/components/layout
export const layout = ({ initialState }:{
  initialState:{settings?: LayoutSettings; menuData:MenuDataItem[];currentUser?:API.CurrentUser}
}):BasicLayoutProps => {
  return {
    rightContentRender: () => <RightContent />,
    disableContentMargin: false,
    footerRender: () => <Footer />,
    onPageChange: () => {

      let menuData = JSON.parse(localStorage.getItem("menuDataList"))
      initialState.menuData = menuData
      const { location } = history;

      //debugger
      console.log(history.location.pathname)
      // scurity user message
      if(initialState.menuData !== null){
        
        console.log("打印userlogin进来了.................")
        let loginarrStr = menuData.filter((item:{path:string;}) => item.path === loginPath)
        console.log(loginarrStr)

        // if(loginarrStr[0].path === loginPath){
        //   history.push(loginPath)
        //   return;
        // }
        
        console.log("数组不为空进来了---------------------")
        let arrStr = menuData.filter((item: { path: string; }) => item.path=== location.pathname)
        //let arrStrPro = menuData.filter((item: { path: string; }) => item.path=== '/user/login/str')
        console.log(arrStr)
        
        if(arrStr.length > 0){
          history.push(arrStr[0].path)
          console.log(arrStr)
        }else{
          history.push('/404')
        }
      }else{
        history.push(loginPath);
      }
      
      console.log("app.tsx-------------------------------------------------------------onPageChange---")
      // console.log(menuData)
      
     
      
      console.log(initialState)
      //console.log(menuData)
      // 如果没有登录,重定向到 login
      if (!initialState?.currentUser && location.pathname !== loginPath) {
        history.push(loginPath);
        return;
      }

      
      
    },
    menuHeaderRender: undefined,
    menuDataRender:(menuData)=> initialState.menuData || menuData,
    ...initialState?.settings,
  };
};

2.user/login/index.tsx 页面配置
该页面集成了登陆预加载,判断用户是否存在

import {
  AlipayCircleOutlined,
  ApiFilled,
  LockOutlined,
  MobileOutlined,
  TaobaoCircleOutlined,
  UserOutlined,
  WeiboCircleOutlined,
} from '@ant-design/icons';
import { Alert, Space, message, Tabs } from 'antd';
import React, { useState } from 'react';
import ProForm, { ProFormCaptcha, ProFormCheckbox, ProFormText } from '@ant-design/pro-form';
import { useIntl, Link, history, FormattedMessage, SelectLang, useModel } from 'umi';
import Footer from '@/components/Footer';
import { login } from '@/services/ant-design-pro/api';
import { getFakeCaptcha } from '@/services/ant-design-pro/login';
import {userLogins,userCurrentUser} from '@/services/user-login/userLogin'

import styles from './index.less';
import { initial } from 'lodash';

const LoginMessage: React.FC<{
  content: string;
}> = ({ content }) => (
  <Alert
    style={{
      marginBottom: 24,
    }}
    message={content}
    type="error"
    showIcon
  />
);

const Login: React.FC = () => {
  const [submitting, setSubmitting] = useState(false);
  const [userLoginState, setUserLoginState] = useState<API.LoginResult>({});
  const [type, setType] = useState<string>('account');
  const { initialState, setInitialState } = useModel('@@initialState');

  const intl = useIntl();

  const fetchUserInfo = async (params:API.LoginParams) => {

    console.log("start-------------------------reqest  ")
    const userInfo = await initialState?.fetchUserInfo?.(params);
    if (userInfo) {
      await setInitialState((s) => ({
        ...s,
        currentUser: userInfo,
      }));
    }

    let currentUsers = JSON.parse(localStorage.getItem("userinfo")) || {}

    console.log(currentUsers)
    console.log(userInfo)
    console.log(initialState)

  };

  const handleSubmit = async (values: API.LoginParams) => {
    setSubmitting(true);
    try {
      console.log({...values})
      // 登录
      const msg = await userLogins({ ...values, type });
      console.log(msg)
      if (msg.status === 'ok') {
        const defaultloginSuccessMessage = intl.formatMessage({
          id: 'pages.login.success',
          defaultMessage: '登录成功!',
        });
        message.success(defaultloginSuccessMessage);

        console.log({...values})

        await fetchUserInfo({...values});
        /** 此方法会跳转到 redirect 参数所在的位置 */
        if (!history) return;
        const { query } = history.location;
        const { redirect } = query as { redirect: string };
        history.push(redirect || '/');
        
        console.log(query) //redirect: "/welcome"
        console.log(redirect) ///welcome
        console.log(msg)  // response new 

        return;
      }
      // 如果失败去设置用户错误信息
      setUserLoginState(msg);
    } catch (error) {
      const defaultloginFailureMessage = intl.formatMessage({
        id: 'pages.login.failure',
        defaultMessage: '登录失败,请重试!',
      });

      message.error(defaultloginFailureMessage);
    }
    setSubmitting(false);
  };
  
  console.log("print path----------------------------------")
  console.log(history.location.pathname)


  const { status, type: loginType } = userLoginState;

  return (
    <div className={styles.container}>
      <div className={styles.lang} data-lang>
        {SelectLang && <SelectLang />}
      </div>
      <div className={styles.content}>
        <div className={styles.top}>
          <div className={styles.header}>
            <Link to="/">
              <div className={styles.logo}>logo</div>
              {/* <img alt="logo" className={styles.logo} src="/logo.svg" /> */}
              {/* <span className={styles.title}>Ant Design</span> */}
            </Link>
          </div>
          <div className={styles.desc}>
            {intl.formatMessage({ id: 'pages.layouts.userLayout.title' })}
          </div>
        </div>

        <div className={styles.main}>
          <ProForm
            initialValues={{
              autoLogin: true,
            }}
            submitter={{
              searchConfig: {
                submitText: intl.formatMessage({
                  id: 'pages.login.submit',
                  defaultMessage: '登录',
                }),
              },
              render: (_, dom) => dom.pop(),
              submitButtonProps: {
                loading: submitting,
                size: 'large',
                style: {
                  width: '100%',
                },
              },
            }}
            onFinish={async (values) => {
              handleSubmit(values as API.LoginParams);
            }}
          >
            {/* <Tabs activeKey={type} onChange={setType}>
              <Tabs.TabPane
                key="account"
                tab={intl.formatMessage({
                  id: 'pages.login.accountLogin.tab',
                  defaultMessage: '账户密码登录',
                })}
              />
              <Tabs.TabPane
                key="mobile"
                tab={intl.formatMessage({
                  id: 'pages.login.phoneLogin.tab',
                  defaultMessage: '手机号登录',
                })}
              />
            </Tabs> */}

            {status === 'error' && loginType === 'account' && (
              <LoginMessage
                content={intl.formatMessage({
                  id: 'pages.login.accountLogin.errorMessage',
                  defaultMessage: '账户或密码错误(admin/ant.design)',
                })}
              />
            )}
            {type === 'account' && (
              <>
                <ProFormText
                  name="username"
                  fieldProps={{
                    size: 'large',
                    prefix: <UserOutlined className={styles.prefixIcon} />,
                  }}
                  placeholder={intl.formatMessage({
                    id: 'pages.login.username.placeholder',
                    defaultMessage: '用户名: admin or user',
                  })}
                  //initialValue={"admin"}
                  rules={[
                    {
                      required: true,
                      message: (
                        <FormattedMessage
                          id="pages.login.username.required"
                          defaultMessage="请输入用户名!"
                        />
                      ),
                    },
                  ]}
                />
                <ProFormText.Password
                  name="password"
                  fieldProps={{
                    size: 'large',
                    prefix: <LockOutlined className={styles.prefixIcon} />,
                  }}
                  placeholder={intl.formatMessage({
                    id: 'pages.login.password.placeholder',
                    defaultMessage: '密码: ant.design',
                    
                  })}
                  initialValue={"ant.design"}
                  rules={[
                    {
                      required: true,
                      message: (
                        <FormattedMessage
                          id="pages.login.password.required"
                          defaultMessage="请输入密码!"
                        />
                      ),
                    },
                  ]}
                />
              </>
            )}
{/* 
            {status === 'error' && loginType === 'mobile' && <LoginMessage content="验证码错误" />}
            {type === 'mobile' && (
              <>
                <ProFormText
                  fieldProps={{
                    size: 'large',
                    prefix: <MobileOutlined className={styles.prefixIcon} />,
                  }}
                  name="mobile"
                  placeholder={intl.formatMessage({
                    id: 'pages.login.phoneNumber.placeholder',
                    defaultMessage: '手机号',
                  })}
                  rules={[
                    {
                      required: true,
                      message: (
                        <FormattedMessage
                          id="pages.login.phoneNumber.required"
                          defaultMessage="请输入手机号!"
                        />
                      ),
                    },
                    {
                      pattern: /^1\d{10}$/,
                      message: (
                        <FormattedMessage
                          id="pages.login.phoneNumber.invalid"
                          defaultMessage="手机号格式错误!"
                        />
                      ),
                    },
                  ]}
                />
                <ProFormCaptcha
                  fieldProps={{
                    size: 'large',
                    prefix: <LockOutlined className={styles.prefixIcon} />,
                  }}
                  captchaProps={{
                    size: 'large',
                  }}
                  placeholder={intl.formatMessage({
                    id: 'pages.login.captcha.placeholder',
                    defaultMessage: '请输入验证码',
                  })}
                  captchaTextRender={(timing, count) => {
                    if (timing) {
                      return `${count} ${intl.formatMessage({
                        id: 'pages.getCaptchaSecondText',
                        defaultMessage: '获取验证码',
                      })}`;
                    }
                    return intl.formatMessage({
                      id: 'pages.login.phoneLogin.getVerificationCode',
                      defaultMessage: '获取验证码',
                    });
                  }}
                  name="captcha"
                  rules={[
                    {
                      required: true,
                      message: (
                        <FormattedMessage
                          id="pages.login.captcha.required"
                          defaultMessage="请输入验证码!"
                        />
                      ),
                    },
                  ]}
                  onGetCaptcha={async (phone) => {
                    const result = await getFakeCaptcha({
                      phone,
                    });
                    if (result === false) {
                      return;
                    }
                    message.success('获取验证码成功!验证码为:1234');
                  }}
                />
              </>
            )} */}
            <div
              style={{
                marginBottom: 24,
              }}
            >
              <ProFormCheckbox noStyle name="autoLogin">
                <FormattedMessage id="pages.login.rememberMe" defaultMessage="自动登录" />
              </ProFormCheckbox>
              <a
                style={{
                  float: 'right',
                }}
              >
                <FormattedMessage id="pages.login.forgotPassword" defaultMessage="忘记密码" />
              </a>
            </div>
          </ProForm>
          <Space className={styles.other}>
            {/* <FormattedMessage id="pages.login.loginWith" defaultMessage="其他登录方式" />
            <AlipayCircleOutlined className={styles.icon} />
            <TaobaoCircleOutlined className={styles.icon} />
            <WeiboCircleOutlined className={styles.icon} /> */}
          </Space>
        </div>
      </div>
      <Footer />
    </div>
  );
};

export default Login;

3,数据的请求Request Umi集成
api user-list的请求事例

// @ts-ignore
/* eslint-disable */
import { request } from 'umi';

/** 获取当前的用户 GET /api/currentUser */
export async function userList(
  params?:API.Item
) {
  return request<{
    data: API.UserItem;
  }>('http://localhost:9999/api/user/findAll/'+params?.page+'/'+params?.limit, {
    method: 'POST',
    data:params
  });
}


/**修改用户信息 */
export async function userUpdate(
  params:API.Item
){
return request<{data:number}>(
  "http://localhost:9999/api/user/update",{
    method:"PUT",
    data:params
  });
}


/**删除用户信息 */
export async function userDelete(id:number){
return request<{data:number}>(
  "http://localhost:9999/api/user/delete/"+id,{
    method:"DELETE",
  });
}


/**新增用户信息 */
export async function userInputAdd(
  params:API.Item
){
  return request<{data:number}>(
    "http://localhost:9999/api/user/input/add",{
      method:"POST",
      data:params
    });
}

/***获取统计信息 */
export async function userCoutnList() {
  return request<{
    data: API.ZgUserCountList;
  }>('http://localhost:9999/api/user/address/count/list', {
    method: 'GET',
  });
}

api UserLogin请求事例

// @ts-ignore
/* eslint-disable */
import { request } from 'umi';


/** 登录接口 POST /api/login/account */
export async function userLogins(body: API.LoginParams, options?: { [key: string]: any }) {
  return request<API.LoginResult>('http://localhost:9999/api/user/login/account', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    data: body,
    ...(options || {}),
  });
}


/** 获取当前的用户 GET /api/currentUser */
export async function userCurrentUser(
  params?:API.LoginParams
) {
  return request<{
    data: API.CurrentUser;
  }>('http://localhost:9999/api/user/login/currentUser', {
    method: 'POST',
    data:params
  });
}



api user-menu 动态菜单渲染请求事例

// @ts-ignore
/* eslint-disable */
import { request } from 'umi';


/** 获取当前的用户 GET /api/currentUser */
export async function userMenuList() {
  return request<{
    data: API.Routes;
  }>('http://localhost:9999/api/user/menu/list', {
    method: 'GET',
  });
}



本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Ant design Pro V5 +Typescript + Hooks + Umi + Dev + SpringBoot + mysql + redis + scrity 实现动态菜单权限管理 的相关文章

随机推荐

  • JAVA使用线程池查询大批量数据

    前言 在开发过程中可能会碰到某些独特的业务 比如查询全部表数据 数据量过多会导致查询变得十分缓慢 虽然在大多数情况下并不需要查询所有的数据 而是通过分页或缓存的形式去减少或者避免这个问题 但是仍然存在需要这样的场景 比如需要导出所有的数据到
  • 论文笔记(四):影像图中水体识别与提取技术研究综述

    快速并且准确地提取水体信息 在水资源规划和调查 预防洪水灾 害和船舶航行中具有重要意义 0 前言 1 遥感图像与人工勘测 遥感图像 成像周期相对较短 实时性强 不受地域限制 人工勘测 耗费大量的人力物力以及时间 2 水体识别方法 阈值法 操
  • C语言字符数组和字符串

    http c biancheng net cpp html 2921 html 用来存放字符的数组称为字符数组 例如 char a 10 一维字符数组 char b 5 10 二维字符数组 char c 20 c p r o g r a m
  • ★教程2:fpga学习教程入门100例目录

    1 订阅本教程用户可以免费获得本博任意2个 包括所有免费专栏和付费专栏 博文对应代码 私信博主给出代码博文的链接和邮箱 2 本FPGA课程的所有案例 部分理论知识点除外 均由博主编写而成 供有兴趣的朋友们自己订阅学习使用 未经本人允许 禁止
  • AI系统论文阅读:SmartMoE

    提出稀疏架构是为了打破具有密集架构的DNN模型中模型大小和计算成本之间的连贯关系的 最著名的MoE MoE模型将传统训练模型中的layer换成了多个expert sub networks 对每个输入 都有一层special gating n
  • 这款毕设至少得收一千五,Python实现学生教师刷脸签到系统。

    背景 今天我在母校群又接到了一个做毕业设计的单子 论题 用Python或者Java实现学生教师刷脸签到系统 一般来讲做学生信息管理系统收500 这个大家觉得报价1500贵吗 我先带大家看干货 简介 利用Python语言 Flask框架 Dl
  • mysql查询时加不加引号的问题

    在查询mysql时碰到了查询条件加引号和不加引号的问题 一 如果字段本身是int类型 如果查询条件中加了引号 比如select from user where id 4 这时候可以查出id 4的用户信息 但是使用select from us
  • 打开mysql的步骤。

    安装mysql软件之后 打开mysql 显示error Can t connect to MySQL server on localhost 10061 原因是服务器没开 这个时候workbench连接不上 然后client登录不上 总结m
  • 2023华为OD机试真题【星际篮球争霸赛/动态规划】

    题目描述 在星球争霸篮球赛对抗赛中 最大的宇宙战队希望每个人都能拿到MVP MVP的条件是单场最高分得分获得者 可以并列所以宇宙战队决定在比赛中尽可能让更多队员上场 并且让所有得分的选手得分都相同 然而比赛过程中的每1分钟的得分都只能由某一
  • Radxa Rock 3a NPU调用指南

    0x0 Radxa Rock 3a开发板介绍 Radxa Rock 3a开发板是基于瑞芯微RK3568芯片设计的 ARM CPU采用4核Cortex A55 Cortex A53的继任者 主频最高可达2 0Ghz CPU性能相当于中高端手机
  • paramiko sftp 问题记录

    paramiko 是一款非常优秀得远程ssh库 能够ssh远程到主机 并执行命令 而且还能通过sftp连接主机 笔者得测试环境 因为安全关系 ssh默认端口修改成其他端口 再往上查阅资料 连接sftp 代码 t paramiko Trans
  • 坐标移动c语言,C语言 坐标移动详解及实例代码

    搜索热词 题目描述 开发一个坐标计算工具 A表示向左移动 D表示向右移动 W表示向上移动 S表示向下移动 从 0 0 点开始移动 从输入字符串里面读取一些坐标 并将最终输入结果输出到输出文件里面 输入 合法坐标为A 或者D或者W或者S 数字
  • 【狂神说】Mybatis学习笔记(全)

    文章目录 前言 1 简介 1 1 什么是MyBatis 1 2 如何获得Mybatis 1 3 持久化 1 3 1 数据持久化 1 3 2 为什么需要持久化 1 4 持久层 1 5 为什么需要MyBatis 2 第一个Mybatis程序 2
  • 《IT项目管理》-大题&计算题保分秘籍

    经过今天的努力 已经把大部分大题和计算题全部总结完了 希望对你们有用 查看链接自取 百度网盘 APP即可获取 链接 https pan baidu com s 1U0EFY23KgTtM8lKlYnjrug pwd tehx 提取码 teh
  • 软考-嵌入式系统设计师-笔记:历年专业英语题

    文章目录 2020年 2019年 2018年 2017年 2016年 2015年 2014年 2013年 2020年 题目 加粗的为各题答案 Fog computing is a mid layer between cloud data c
  • deepIn 、 DDE 系统桌面黑屏解决方案

    桌面黑屏有两种情况 1 桌面除了底部菜单栏 其它全是黑的 解决方案 Deepin sudo apt install reinstall dde DDE sudo apt fix broken install sudo apt install
  • 基于SpringBoot和vue的若依后台管理系统 部署

    RuoYi Vue是一款前后端分离的极速后台开发框架 基于SpringBoot和Vue 目录 一 准备 二 启动前端项目 解决报错 digital envelope routines unsupported 测试 三 启动后端项目 四 运行
  • 8个适合新手的Python小项目

    这是我挑出来的8个适合新手的小项目 涉及了爬虫 多线程 selenium PhantomJs itchat 邮件发送 crontab 命令行颜色显示 excel操作 PIL 识别验证码 首先说明 天下没有免费的午餐 每个项目平均下来2元多一
  • 根据子网掩码算出 IP 地址 的网络号和主机号

    我们如何根据子网掩码算出 IP 地址 的网络号和主机号呢 举个例子 比如 10 100 122 0 24 后面的 24表示就是 255 255 255 0 子网掩码 255 255 255 0 二进制是 11111111 11111111
  • Ant design Pro V5 +Typescript + Hooks + Umi + Dev + SpringBoot + mysql + redis + scrity 实现动态菜单权限管理

    Ant design Pro V5 Typescript Hooks Umi Dev SpringBoot mysql redis scrity 实现动态菜单权限管理 企业中台架构 1 app tsx页面配置 该页面集成了登陆权限控制 动态