455 lines
14 KiB
TypeScript
455 lines
14 KiB
TypeScript
import { history } from 'umi';
|
||
import {
|
||
userLogin, retrieveUserInfo, retrieveUserInfoAuthorityMenu, userLogout,
|
||
retrieveUserAuthorityMenu,
|
||
} from '@/services/user';
|
||
import type { Effect, Reducer, ConnectProps } from 'umi';
|
||
import handleRedirect from '@/utils/handleRedirect';
|
||
import handleGetRootSubmenuKeys from '@/utils/handleGetRootSubmenuKeys';
|
||
import handleGetEachDatumFromNestedDataByKey from '@/utils/handleGetEachDatumFromNestedDataByKey';
|
||
import handleGetIndexValidMenuItemByPath from '@/utils/handleGetIndexValidMenuItemByPath';
|
||
import { notification } from 'antd';
|
||
|
||
/**
|
||
* 全局用户数据
|
||
* @description isLogin 是否登录过
|
||
* @description data 用户信息
|
||
* @description menu 菜单数据
|
||
* @description authority 权限数组
|
||
* @description loginBtnLoading 按钮loading状态
|
||
* @description rootSubmenuKeys 子菜单的父级菜单key
|
||
* @description layoutWrapperLoading 布局外层容器loading状态
|
||
* @description indexAllMenuItemById 通过id索引索引菜单项的映射
|
||
* @description indexAllMenuItemByPath 通过path索引所有菜单项的映射
|
||
* @description indexValidMenuItemByPath 通过path索引有效菜单项的映射
|
||
*/
|
||
export type UserModelState = {
|
||
isLogin: boolean;
|
||
data: API.UserInfo;
|
||
menu: API.MenuData;
|
||
authority: string[];
|
||
loginBtnLoading: boolean;
|
||
rootSubmenuKeys: React.Key[];
|
||
layoutWrapperLoading: boolean;
|
||
indexAllMenuItemById: IndexAllMenuItemByKey<'id'>;
|
||
indexValidMenuItemByPath: IndexValidMenuItemByPath;
|
||
indexAllMenuItemByPath: IndexAllMenuItemByKey<'path'>;
|
||
}
|
||
|
||
export type UserConnectedProps = {
|
||
user: UserModelState;
|
||
} & ConnectProps;
|
||
|
||
type UserModelType = {
|
||
namespace: 'user';
|
||
state: UserModelState;
|
||
effects: {
|
||
login: Effect;
|
||
logout: Effect;
|
||
resetLoginStatus: Effect;
|
||
getUserInfoAuthorityMenu: Effect;
|
||
};
|
||
reducers: {
|
||
save: Reducer<UserModelState>;
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 请求顺序
|
||
* @description 并发 | 继发
|
||
*/
|
||
type ReqOrder = 'concurrent' | 'relay';
|
||
|
||
const UserModel: UserModelType = {
|
||
namespace: 'user',
|
||
state: {
|
||
data: {},
|
||
authority: [],
|
||
isLogin: false,
|
||
rootSubmenuKeys: [],
|
||
loginBtnLoading: false,
|
||
layoutWrapperLoading: true,
|
||
menu: [
|
||
|
||
],
|
||
indexAllMenuItemById: {
|
||
|
||
},
|
||
indexAllMenuItemByPath: {
|
||
|
||
},
|
||
indexValidMenuItemByPath: {
|
||
|
||
},
|
||
},
|
||
effects: {
|
||
//登录
|
||
*login({ payload }, { call, put, select }) {
|
||
// 检查当前是否已经在登录状态
|
||
const { isLogin } = yield select((state) => state.user);
|
||
if (isLogin) {
|
||
return { code: 1, message: '您已经登录' };
|
||
}
|
||
|
||
// 检查是否有payload,防止自动触发
|
||
if (!payload) {
|
||
return { code: 1, message: '登录参数无效' };
|
||
}
|
||
|
||
yield put({
|
||
type: 'save',
|
||
payload: {
|
||
loginBtnLoading: true,
|
||
},
|
||
});
|
||
|
||
try {
|
||
const res: API.LoginResponse = yield call(userLogin, payload);
|
||
console.log('res', res);
|
||
|
||
if (res.code === 200) {
|
||
localStorage.setItem('Authorization', res.data.accessToken);
|
||
|
||
yield put({
|
||
type: 'getUserInfoAuthorityMenu',
|
||
payload: {
|
||
type: 'concurrent',
|
||
},
|
||
});
|
||
return res;
|
||
} else {
|
||
yield put({
|
||
type: 'save',
|
||
payload: {
|
||
loginBtnLoading: false,
|
||
},
|
||
});
|
||
return { code: res.code, message: res.message };
|
||
}
|
||
} catch (error) {
|
||
yield put({
|
||
type: 'save',
|
||
payload: {
|
||
loginBtnLoading: false,
|
||
},
|
||
});
|
||
return { code: 1, message: error?.message || '登录失败,请稍后重试' };
|
||
}
|
||
},
|
||
//获取用户信息和权限以及菜单
|
||
*getUserInfoAuthorityMenu({ payload }, { call, put }) {
|
||
// const { type }: { type: ReqOrder } = payload;
|
||
|
||
// // 如果当前在登录页面,且不是通过登录操作触发,则不执行后续操作
|
||
// if (window.location.pathname === '/user/login' && type !== 'concurrent') {
|
||
// yield put({
|
||
// type: 'save',
|
||
// payload: {
|
||
// layoutWrapperLoading: false,
|
||
// isLogin: false // 确保在登录页面时重置登录状态
|
||
// },
|
||
// });
|
||
// return false;
|
||
// }
|
||
|
||
let userInfoRes: API.UserInfoResponse = {
|
||
data: {},
|
||
code: 0,
|
||
message: '',
|
||
};
|
||
|
||
// let userAuthorityRes: API.UserAuthorityResponse = {
|
||
// data: {
|
||
// authority: [],
|
||
// },
|
||
// code: 0,
|
||
// message: '',
|
||
// };
|
||
|
||
let menuRes: API.MenuDataResponse = {
|
||
data: [],
|
||
code: 0,
|
||
message: '',
|
||
};
|
||
|
||
// //用户在登录页登录完成之后执行
|
||
// if (type === 'concurrent') {
|
||
// const res: API.UserInfoAuthMenuResponse = yield call(retrieveUserInfoAuthorityMenu);
|
||
// console.log('res', res);
|
||
// userInfoRes = res[0] as API.UserInfoResponse;
|
||
// // userAuthorityRes = res[1] as API.UserAuthorityResponse;
|
||
// menuRes = res[1] as API.MenuDataResponse;
|
||
// } else {
|
||
// //其他情形首先查询用户的登录状态, 未登录则不继续操作
|
||
// try {
|
||
// userInfoRes = yield call(retrieveUserInfo);
|
||
// } catch (error) {
|
||
// //接口报错了, 比如返回了401
|
||
// yield put({
|
||
// type: 'save',
|
||
// payload: {
|
||
// layoutWrapperLoading: false,
|
||
// },
|
||
// });
|
||
|
||
// // 只有在非登录页面时才执行重定向
|
||
// if (window.location.pathname !== '/user/login') {
|
||
// yield put({
|
||
// type: 'resetLoginStatus',
|
||
// });
|
||
// }
|
||
|
||
// return false;
|
||
// }
|
||
|
||
// const res: API.UserAuthMenuResponse = yield call(retrieveUserAuthorityMenu);
|
||
// // userAuthorityRes = res[0] as API.UserAuthorityResponse;
|
||
// menuRes = res[0] as API.MenuDataResponse;
|
||
// }
|
||
|
||
// console.log('userInfoRes', userInfoRes);
|
||
|
||
menuRes.data = [
|
||
{
|
||
path: '/',
|
||
redirect: '',
|
||
name: '',
|
||
children: [
|
||
{
|
||
path: '/test/index',
|
||
redirect: '',
|
||
name: '测试',
|
||
component: "@/pages/test/index",
|
||
},
|
||
{
|
||
path: '/Invoicing/index',
|
||
redirect: '',
|
||
name: '开票管理',
|
||
component: "@/pages/Invoicing/index",
|
||
},
|
||
{
|
||
path: '/DigitalElectronics/index',
|
||
redirect: '',
|
||
name: '开票管理',
|
||
component: "@/pages/DigitalElectronics/index",
|
||
},
|
||
{
|
||
path: '/redReversal/index',
|
||
redirect: '',
|
||
name: '红冲管理',
|
||
component: "@/pages/redReversal/index",
|
||
},
|
||
{
|
||
path: '/InvoiceInquiry/index',
|
||
redirect: '',
|
||
name: '开票查询',
|
||
component: "@/pages/InvoiceInquiry/index",
|
||
},
|
||
{
|
||
path: '/InvoiceSearch/index',
|
||
redirect: '',
|
||
name: '开票查询',
|
||
component: "@/pages/InvoiceSearch/index",
|
||
},
|
||
{
|
||
path: '/serverpartAssets/index',
|
||
redirect: '',
|
||
name: '服务区资产管理',
|
||
component: "@/pages/serverpartAssets/index",
|
||
},
|
||
{
|
||
path: '/operationReport/index',
|
||
redirect: '',
|
||
name: '运营报表',
|
||
component: "@/pages/operationReport/index",
|
||
},
|
||
{
|
||
path: '/operationReport/routineInspection',
|
||
redirect: '',
|
||
name: '日常巡检记录表',
|
||
component: "@/pages/operationReport/routineInspection",
|
||
},
|
||
{
|
||
path: '/operationReport/onSiteInspection',
|
||
redirect: '',
|
||
name: '现场巡检记录表',
|
||
component: "@/pages/operationReport/onSiteInspection",
|
||
},
|
||
{
|
||
path: '/operationReport/securityIssueList',
|
||
redirect: '',
|
||
name: '安全问题记录表',
|
||
component: "@/pages/operationReport/securityIssueList",
|
||
},
|
||
{
|
||
path: '/operationReport/rectificationStatus',
|
||
redirect: '',
|
||
name: '整改情况追踪表',
|
||
component: "@/pages/operationReport/rectificationStatus",
|
||
},
|
||
{
|
||
path: '/RentCalculation/index',
|
||
redirect: '',
|
||
name: '租金测算',
|
||
component: "@/pages/RentCalculation/index",
|
||
},
|
||
{
|
||
path: '/rentComparison/index',
|
||
redirect: '',
|
||
name: '租金对比',
|
||
component: "@/pages/rentComparison/index",
|
||
},
|
||
{
|
||
path: '/realEstate/index',
|
||
redirect: '',
|
||
name: '不动产管理',
|
||
component: "@/pages/realEstate/index",
|
||
},
|
||
]
|
||
}
|
||
|
||
]
|
||
// menuRes.data = [
|
||
// {
|
||
// path: '/standard/index',
|
||
// redirect: '',
|
||
// name: '生成标准页面',
|
||
// component: "@/pages/standard/index",
|
||
// },
|
||
// {
|
||
// path: '/examine',
|
||
// redirect: '',
|
||
// name: '走动式管理',
|
||
// children: [
|
||
// {
|
||
// path: '/examine/index',
|
||
// name: '考评分类管理',
|
||
// component: "@/pages/examine/index",
|
||
// },
|
||
// {
|
||
// path: '/examine/question',
|
||
// name: '考核问题管理',
|
||
// component: "@/pages/examine/question",
|
||
// },
|
||
// {
|
||
// path: '/examine/modal',
|
||
// name: '考核模版管理',
|
||
// component: "@/pages/examine/modal",
|
||
// },
|
||
// {
|
||
// path: '/examine/record',
|
||
// name: '考核记录管理',
|
||
// component: "@/pages/examine/record",
|
||
// }
|
||
// ]
|
||
|
||
// },
|
||
// ]
|
||
let indexAllMenuItemByPath: any = []
|
||
let indexValidMenuItemByPath: any = []
|
||
if (menuRes.data && menuRes.data.length > 0) {
|
||
indexAllMenuItemByPath = handleGetEachDatumFromNestedDataByKey(menuRes.data, 'path');
|
||
indexValidMenuItemByPath = handleGetIndexValidMenuItemByPath(menuRes.data);
|
||
}
|
||
|
||
//在登录完获取菜单数据之后做是否需要重定向的操作
|
||
yield call(
|
||
handleRedirect,
|
||
window.location.pathname === '/cloudMenu/user/login',
|
||
indexAllMenuItemByPath,
|
||
indexValidMenuItemByPath,
|
||
);
|
||
|
||
yield put({
|
||
type: 'save',
|
||
payload: {
|
||
isLogin: true,
|
||
menu: menuRes.data,
|
||
data: userInfoRes.data,
|
||
loginBtnLoading: false,
|
||
indexAllMenuItemByPath,
|
||
indexValidMenuItemByPath,
|
||
layoutWrapperLoading: false,
|
||
// authority: userAuthorityRes.data.authority,
|
||
authority: [
|
||
'/test/index',
|
||
'/cloudMenu/test/index',
|
||
"/Invoicing/index",
|
||
"/DigitalElectronics/index",
|
||
"/InvoiceInquiry/index",
|
||
"/redReversal/index",
|
||
"/InvoiceSearch/index",
|
||
"/serverpartAssets/index",
|
||
"/operationReport/index",
|
||
"/operationReport/routineInspection",
|
||
"/operationReport/onSiteInspection",
|
||
"/operationReport/securityIssueList",
|
||
"/operationReport/rectificationStatus",
|
||
"/RentCalculation/index",
|
||
"/rentComparison/index",
|
||
"/realEstate/index",
|
||
// '/examine/index',
|
||
// '/examine/modal',
|
||
// '/examine/question',
|
||
// '/examine/record',
|
||
],
|
||
rootSubmenuKeys: handleGetRootSubmenuKeys(menuRes.data),
|
||
indexAllMenuItemById: handleGetEachDatumFromNestedDataByKey(menuRes.data, 'id'),
|
||
},
|
||
});
|
||
//为保证所有语句都return, 因此这里加一句这个
|
||
return true;
|
||
},
|
||
//登出
|
||
* logout({ payload }, { call, put }) {
|
||
const res: API.LogoutResponse = yield call(userLogout, payload);
|
||
console.log('res', res)
|
||
if (res.code === 200) {
|
||
yield put({
|
||
type: 'resetLoginStatus',
|
||
});
|
||
}
|
||
},
|
||
//重置登录状态
|
||
* resetLoginStatus(_, { put }) {
|
||
localStorage.removeItem('Authorization');
|
||
|
||
yield put({
|
||
type: 'save',
|
||
payload: {
|
||
isLogin: false,
|
||
loginBtnLoading: false,
|
||
},
|
||
});
|
||
|
||
//当前页面不是登录页时,才进行重定向
|
||
if (window.location.pathname !== '/user/login') {
|
||
// 只获取路径部分,不包含查询参数,避免redirect参数累积
|
||
let redirectValue = window.location.pathname;
|
||
|
||
// 检查是否有base路径重复问题
|
||
if (redirectValue.startsWith('/') && redirectValue.indexOf('/', 1) !== -1) {
|
||
const firstSlashAfterRoot = redirectValue.indexOf('/', 1);
|
||
const possiblePrefix = redirectValue.substring(0, firstSlashAfterRoot);
|
||
// 检查是否有重复的路径前缀
|
||
if (redirectValue.indexOf(possiblePrefix, firstSlashAfterRoot) === firstSlashAfterRoot) {
|
||
redirectValue = redirectValue.substring(firstSlashAfterRoot);
|
||
}
|
||
}
|
||
|
||
// history.push(`/user/login?redirect=${encodeURIComponent(redirectValue)}`);
|
||
}
|
||
},
|
||
},
|
||
reducers: {
|
||
save(state, action) {
|
||
return {
|
||
...state,
|
||
...action.payload,
|
||
};
|
||
},
|
||
},
|
||
};
|
||
|
||
export default UserModel;
|