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',});
}