当前位置: 代码迷 >> 综合 >> Ant design Pro V5 +Typescript + Hooks + Umi + Dev + SpringBoot + mysql + redis + scrity 实现动态菜单权限管理
  详细解决方案

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

热度:61   发布时间:2023-11-14 13:21:14.0

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 loginconst 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 = menuDataconst {
     location } = history;//debuggerconsole.log(history.location.pathname)// scurity user messageif(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)// 如果没有登录,重定向到 loginif (!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 }) => (<Alertstyle={
    {
    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) ///welcomeconsole.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}><ProForminitialValues={
    {
    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.TabPanekey="account"tab={intl.formatMessage({id: 'pages.login.accountLogin.tab',defaultMessage: '账户密码登录',})}/><Tabs.TabPanekey="mobile"tab={intl.formatMessage({id: 'pages.login.phoneLogin.tab',defaultMessage: '手机号登录',})}/></Tabs> */}{
    status === 'error' && loginType === 'account' && (<LoginMessagecontent={
    intl.formatMessage({
    id: 'pages.login.accountLogin.errorMessage',defaultMessage: '账户或密码错误(admin/ant.design)',})}/>)}{
    type === 'account' && (<><ProFormTextname="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: (<FormattedMessageid="pages.login.username.required"defaultMessage="请输入用户名!"/>),},]}/><ProFormText.Passwordname="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: (<FormattedMessageid="pages.login.password.required"defaultMessage="请输入密码!"/>),},]}/></>)}
{
    /* {status === 'error' && loginType === 'mobile' && <LoginMessage content="验证码错误" />}{type === 'mobile' && (<><ProFormTextfieldProps={
    {size: 'large',prefix: <MobileOutlined className={styles.prefixIcon} />,}}name="mobile"placeholder={intl.formatMessage({id: 'pages.login.phoneNumber.placeholder',defaultMessage: '手机号',})}rules={[{required: true,message: (<FormattedMessageid="pages.login.phoneNumber.required"defaultMessage="请输入手机号!"/>),},{pattern: /^1\d{10}$/,message: (<FormattedMessageid="pages.login.phoneNumber.invalid"defaultMessage="手机号格式错误!"/>),},]}/><ProFormCaptchafieldProps={
    {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: (<FormattedMessageid="pages.login.captcha.required"defaultMessage="请输入验证码!"/>),},]}onGetCaptcha={async (phone) => {const result = await getFakeCaptcha({phone,});if (result === false) {return;}message.success('获取验证码成功!验证码为:1234');}}/></>)} */}<divstyle={
    {
    marginBottom: 24,}}><ProFormCheckbox noStyle name="autoLogin"><FormattedMessage id="pages.login.rememberMe" defaultMessage="自动登录" /></ProFormCheckbox><astyle={
    {
    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',});
}
  相关解决方案