update
This commit is contained in:
parent
8f84f22e95
commit
beb008c078
11
mock/user.ts
11
mock/user.ts
@ -20,17 +20,12 @@ const handleCommonRes = (data: Record<string, unknown> | Record<string, unknown>
|
||||
const userApi = {
|
||||
//登录
|
||||
'POST /api/user/login': async (req: Request, res: Response) => {
|
||||
console.log('req', req);
|
||||
console.log('res', res);
|
||||
|
||||
return
|
||||
|
||||
const { password, username, mobile, captcha } = req.body;
|
||||
const { UserPassWord, UserPassport, mobile, captcha } = req.body;
|
||||
await waitTime(2000);
|
||||
|
||||
switch (true) {
|
||||
case username === 'admin' && password === 'ant.design':
|
||||
case username === 'user' && password === 'ant.design':
|
||||
case UserPassport === 'admin' && UserPassWord === 'ant.design':
|
||||
case UserPassport === 'user' && UserPassWord === 'ant.design':
|
||||
case /^1\d{10}$/.test(mobile) && Boolean(captcha):
|
||||
res.send(
|
||||
handleCommonRes({
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
.proLayoutBox{
|
||||
.pageLayout{
|
||||
.ant-layout{
|
||||
.ant-layout-sider{
|
||||
background-color: #021529;
|
||||
background-color: #021529!important;
|
||||
.ant-layout-sider-children{
|
||||
padding: 0;
|
||||
.ant-pro-sider-logo{
|
||||
@ -13,7 +13,7 @@
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
font-size: 18px;
|
||||
line-height: 32px;
|
||||
// line-height: 32px;
|
||||
vertical-align: none;
|
||||
margin-left: 12px;
|
||||
}
|
||||
@ -22,9 +22,6 @@
|
||||
}
|
||||
|
||||
.ant-layout-sider-children{
|
||||
.ant-pro-sider-extra{
|
||||
margin: 0;
|
||||
.ant-layout{
|
||||
ul{
|
||||
li{
|
||||
span{
|
||||
@ -40,8 +37,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -53,4 +48,165 @@
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.tab-extra {
|
||||
width: 13px;
|
||||
height: 15px;
|
||||
padding: 0 26px 16px 0;
|
||||
// background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAAPCAYAAAA/I0V3AAAAAXNSR0IArs4c6QAAANhJREFUOE+9kT1rAlEQRc/MCmLjz7G1tUphKTbpBFs16BpZXkyCuqRLbaFYWqSytc3PSRMC7jxRMMQP5KVxypm5M5dzJXap558ltxN13Vs5skxCHWYa+eDlv0el5yYzRXKhnwy/uSGI2KUZoKH2ANvZawDvgUIDmnt6PTepCzIFrgHZePz9y6A9/0Xef0qr5lkI5E+tevhRoTZ8bC13s6Oc+sm4YqpLgcJB6OFbzarDpLM69M7C7bpxWdEPoAh8GXb3Ouisj8K9RC1ORiU0WmBZ7Tl5+Dzd2QIFbkkh8PpnKgAAAABJRU5ErkJggg==') ;
|
||||
// background-repeat: no-repeat;
|
||||
|
||||
}
|
||||
.ant-dropdown-open svg {
|
||||
// color: @primary-color;
|
||||
// background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAAPCAYAAAA/I0V3AAAAAXNSR0IArs4c6QAAAMZJREFUOE+9kb0KwkAQhGdUEBtfxpxtWisLS7GxE4Too3gH1hZKSgsrW1vj09iIkGQkghJ/kLPJlrs7u8M3NDYX/ixWKHIKlaX0dch6Q97L5aM0i2wN1hq+n6A8rRBEYPOMQM3XnoCcHasJoaWPsBAInN7pmYVGoFYAfgFJIY6TOTdP5MZpICkm0Hy3KuBKcphE3Bazl5yMVQ9QMWiVhBeAg2TG/aP3Ea5xCiHtALQBnEH2k4iHl3C/UQucupBikMNTxOP7zg3x4U00HiX/gwAAAABJRU5ErkJggg==');
|
||||
}
|
||||
.tab-extra:hover {
|
||||
// background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAAPCAYAAAA/I0V3AAAAAXNSR0IArs4c6QAAAMZJREFUOE+9kb0KwkAQhGdUEBtfxpxtWisLS7GxE4Too3gH1hZKSgsrW1vj09iIkGQkghJ/kLPJlrs7u8M3NDYX/ixWKHIKlaX0dch6Q97L5aM0i2wN1hq+n6A8rRBEYPOMQM3XnoCcHasJoaWPsBAInN7pmYVGoFYAfgFJIY6TOTdP5MZpICkm0Hy3KuBKcphE3Bazl5yMVQ9QMWiVhBeAg2TG/aP3Ea5xCiHtALQBnEH2k4iHl3C/UQucupBikMNTxOP7zg3x4U00HiX/gwAAAABJRU5ErkJggg==');
|
||||
}
|
||||
|
||||
.ant-modal-header {
|
||||
background-color: #ecf2f7 !important;
|
||||
border-bottom: none !important;
|
||||
}
|
||||
|
||||
body *::-webkit-scrollbar {
|
||||
/* 滚动条整体样式 */
|
||||
width : 8px; /* 高宽分别对应横竖滚动条的尺寸 */
|
||||
height: 8px;
|
||||
}
|
||||
body *::-webkit-scrollbar-thumb {
|
||||
/* 滚动条里面小方块 */
|
||||
background-color: #d1cfcf;
|
||||
// background-image: -webkit-linear-gradient(
|
||||
// 45deg,
|
||||
// rgba(255, 255, 255, 0.2) 25%,
|
||||
// transparent 25%,
|
||||
// transparent 50%,
|
||||
// rgba(255, 255, 255, 0.2) 50%,
|
||||
// rgba(255, 255, 255, 0.562) 75%,
|
||||
// transparent 75%,
|
||||
// transparent
|
||||
// );
|
||||
border-radius: 10px;
|
||||
}
|
||||
body *::-webkit-scrollbar-track {
|
||||
/* 滚动条里面轨道 */
|
||||
background: #ededed;
|
||||
border-radius: 10px;
|
||||
box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.01);
|
||||
}
|
||||
|
||||
// 列表页左侧多选树
|
||||
.pageTable-leftnav .ant-tree-list-holder{
|
||||
height: calc(100vh - 257px);
|
||||
padding-right: 0;
|
||||
padding-bottom: 0;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.leftHeight .ant-tree-list-holder{
|
||||
height: 100%!important;
|
||||
}
|
||||
.leftHeight .ant-tree-list{
|
||||
height: 560px
|
||||
}
|
||||
.pageTable-leftnavs .ant-tree-list-holder{
|
||||
height: 580px;
|
||||
padding-right: 0;
|
||||
padding-bottom: 0;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.pageTable-leftnav .ant-pro-card-header.ant-pro-card-header-border {
|
||||
padding-top: 29px;
|
||||
}
|
||||
.pageTable-leftnav .ant-pro-card-title {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.pageTable-leftnav .ant-pro-card-split-vertical{
|
||||
transition: width 0.3s;
|
||||
}
|
||||
.pageTable-leftnav .ant-tree .ant-tree-treenode {
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
.pageTable-leftnavs .ant-tree .ant-tree-treenode {
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
.ant-table-tbody > tr.tablerow-no-border > td{
|
||||
border-bottom: 0;
|
||||
}
|
||||
// prolist 卡片类型
|
||||
.ant-pro-list .ant-pro-card-header {
|
||||
padding: 0 !important;
|
||||
}
|
||||
.ant-pro-list .ant-pro-card.ant-pro-card-border.ant-pro-card-hoverable>.ant-pro-card-body {
|
||||
margin: 0 !important;
|
||||
padding: 20px 0 0 0 !important;
|
||||
}
|
||||
|
||||
.ant-pro-list .ant-pro-card.ant-pro-card-border> ul.ant-pro-card-actions {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.ant-pro-list .ant-pro-card.ant-pro-card-border> ul.ant-pro-card-actions >li{
|
||||
margin:0;
|
||||
}
|
||||
.ant-pro-list .ant-pro-card.ant-pro-card-border.ant-pro-card-hoverable> ul.ant-pro-card-actions > li, .ant-pro-list .ant-pro-card .ant-pro-card-actions .ant-space-item {
|
||||
margin: 10px 0 0 0 !important;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
.main-tab >.ant-tabs-nav {
|
||||
margin-bottom: 0 !important;
|
||||
padding: 2px 15px 0 16px;
|
||||
background-color: #fff;
|
||||
}
|
||||
.main-tab > .ant-tabs-nav .ant-tabs-tab {
|
||||
background-color: #fafafa;
|
||||
border-color: #f0f0f0;
|
||||
border-bottom: 0;
|
||||
}
|
||||
.main-tab > .ant-tabs-nav .ant-tabs-tab button svg {
|
||||
// color: #fff;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
.main-tab > .ant-tabs-nav .ant-tabs-tab:hover {
|
||||
background-color:#fafafa;
|
||||
border-color: #f0f0f0;
|
||||
}
|
||||
.main-tab > .ant-tabs-nav .ant-tabs-tab:hover button svg {
|
||||
// color: @link-color;
|
||||
}
|
||||
.main-tab.ant-tabs-top > .ant-tabs-nav .ant-tabs-tab-active {
|
||||
background-color: #f6f9fb;
|
||||
border-color: #f0f0f0;
|
||||
box-shadow: 2px 0 6px 0 #e7e7e7;
|
||||
border-top-color: #3591fe;
|
||||
}
|
||||
.main-tab.ant-tabs-top > .ant-tabs-nav .ant-tabs-tab-active::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
display: block;
|
||||
background-color: #3591fe;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
}
|
||||
.main-tab > .ant-tabs-nav .ant-tabs-tab-active button svg {
|
||||
// color: @icon-color;
|
||||
}
|
||||
.main-tab > .ant-tabs-content-holder {
|
||||
height: calc(100vh - 86px);
|
||||
padding-top: 16px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.main-tab > .ant-tabs-nav .ant-tabs-nav-wrap {
|
||||
bottom: 1px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@ import type { FC } from 'react';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Dropdown, Layout, Menu, Tabs, Tooltip } from 'antd';
|
||||
import type { MenuProps } from 'antd';
|
||||
import { Outlet, Link, useLocation, connect } from 'umi';
|
||||
import { Outlet, Link, useLocation, connect, history } from 'umi';
|
||||
import PageAccess from '@/components/PageAccess';
|
||||
import type { UserConnectedProps, UserModelState } from '@/models/user';
|
||||
import LayoutWrapper from '@/components/LayoutWrapper';
|
||||
@ -18,6 +18,8 @@ import { ProfileModelState } from '@/models/global';
|
||||
import React from 'react';
|
||||
|
||||
const { Header, Content } = Layout;
|
||||
const { TabPane } = Tabs;
|
||||
|
||||
/**
|
||||
* 获取openKeys的方法
|
||||
* @param currentLocation 当前位置, 由handleGetCurrentLocation方法返回
|
||||
@ -43,7 +45,7 @@ const handleGetOpenKeys = (currentLocation: API.MenuItem[] | []): string[] => {
|
||||
};
|
||||
|
||||
//自定义的layout页面, 顶部导航通栏+侧边栏(菜单)布局, 可根据需要做调整
|
||||
const BasicLayout: FC<{ user: UserModelState, global: ProfileModelState, dispatch: any }> = (props) => {
|
||||
const BasicLayout: FC<{ user: UserModelState, global: ProfileModelState, dispatch: any, location: any }> = (props) => {
|
||||
const [collapsed, setCollapsed] = useState(false);
|
||||
const [openKeys, setOpenKeys] = useState(['']);
|
||||
const { pathname } = useLocation();
|
||||
@ -54,11 +56,12 @@ const BasicLayout: FC<{ user: UserModelState, global: ProfileModelState, dispatc
|
||||
indexValidMenuItemByPath
|
||||
},
|
||||
global: {
|
||||
|
||||
tabsRoutes
|
||||
}
|
||||
} = props;
|
||||
|
||||
console.log('props', props);
|
||||
const [activeKey, setActiveKey] = useState<string>('/')
|
||||
|
||||
|
||||
const validMenuItem = indexValidMenuItemByPath[pathname];
|
||||
@ -140,17 +143,103 @@ const BasicLayout: FC<{ user: UserModelState, global: ProfileModelState, dispatc
|
||||
// 改变panes
|
||||
const handleTabsPanes = (payload: any): void => {
|
||||
dispatch({
|
||||
type: "global/saveTabsRoutes",
|
||||
payload: {
|
||||
data: payload,
|
||||
action: 'add'
|
||||
}
|
||||
})
|
||||
type: 'global/changeTabsRoutes',
|
||||
payload: { data: payload, action: 'add' },
|
||||
});
|
||||
};
|
||||
|
||||
// 关闭当前标签
|
||||
const handleEdit = (targetKey: string | React.MouseEvent<Element, MouseEvent> | React.KeyboardEvent<Element>, action: "add" | "remove"): void => {
|
||||
|
||||
if (action === 'remove' && dispatch) {
|
||||
const index = tabsRoutes.findIndex((n: { path: string }) => n.path === targetKey)
|
||||
|
||||
// 定位关闭当前标签后,需要选中的下一个标签
|
||||
// eslint-disable-next-line no-nested-ternary
|
||||
const nextkey = tabsRoutes[index + 1] ? tabsRoutes[index + 1].path : (tabsRoutes[index - 1] ? tabsRoutes[index - 1].path : '')
|
||||
history.push(nextkey || '/')
|
||||
setActiveKey(nextkey)
|
||||
|
||||
// 缓存路由栈数据
|
||||
dispatch({
|
||||
type: 'global/changeTabsRoutes',
|
||||
payload: { data: [targetKey], action },
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// 全部菜单一层的数组
|
||||
const oneFloorList = [
|
||||
{
|
||||
SYSTEMMODULE_DESC: "",
|
||||
guid: "1",
|
||||
hideInMenu: false,
|
||||
name: "首页",
|
||||
path: "/",
|
||||
},
|
||||
{
|
||||
SYSTEMMODULE_DESC: "",
|
||||
guid: "2",
|
||||
hideInMenu: false,
|
||||
name: "关于你1",
|
||||
path: "/about/u/1",
|
||||
},
|
||||
{
|
||||
SYSTEMMODULE_DESC: "",
|
||||
guid: "3",
|
||||
hideInMenu: false,
|
||||
name: "关于你2",
|
||||
path: "/about/u/2",
|
||||
},
|
||||
{
|
||||
SYSTEMMODULE_DESC: "",
|
||||
guid: "4",
|
||||
hideInMenu: false,
|
||||
name: "(页面元素权限)关于我",
|
||||
path: "/about/m",
|
||||
},
|
||||
{
|
||||
SYSTEMMODULE_DESC: "",
|
||||
guid: "5",
|
||||
hideInMenu: false,
|
||||
name: "关于你和我",
|
||||
path: "/about/um",
|
||||
},
|
||||
{
|
||||
SYSTEMMODULE_DESC: "",
|
||||
guid: "5",
|
||||
hideInMenu: false,
|
||||
name: "(403)关于你教师",
|
||||
path: "/teacher/u",
|
||||
},
|
||||
{
|
||||
SYSTEMMODULE_DESC: "",
|
||||
guid: "6",
|
||||
hideInMenu: false,
|
||||
name: "关于我教师",
|
||||
path: "/teacher/m",
|
||||
},
|
||||
{
|
||||
SYSTEMMODULE_DESC: "",
|
||||
guid: "7",
|
||||
hideInMenu: false,
|
||||
name: "关于你和我教师",
|
||||
path: "/teacher/um",
|
||||
},
|
||||
{
|
||||
SYSTEMMODULE_DESC: "",
|
||||
guid: "8",
|
||||
hideInMenu: false,
|
||||
name: "(404)学生",
|
||||
path: "/student",
|
||||
}
|
||||
]
|
||||
|
||||
return (
|
||||
<LayoutWrapper>
|
||||
<ProLayout
|
||||
className={"pageLayout"}
|
||||
logo={logo}
|
||||
contentWidth={"Fluid"}
|
||||
fixedHeader={true}
|
||||
@ -206,11 +295,19 @@ const BasicLayout: FC<{ user: UserModelState, global: ProfileModelState, dispatc
|
||||
onPageChange={(location) => {
|
||||
console.log('location', location);
|
||||
if (location?.pathname && location?.pathname !== '/') {
|
||||
const nextModule = consumableMenu.find(n => location?.pathname && n?.path && location?.pathname.match(n?.path))
|
||||
console.log('nextModule', nextModule);
|
||||
console.log('oneFloorList', oneFloorList);
|
||||
|
||||
// const nextModule = oneFloorList.find(n => location?.pathname && n?.path && location?.pathname.match(n?.path))
|
||||
const nextModule: any = oneFloorList.filter(n => location?.pathname === n?.path)
|
||||
console.log('nextModule', nextModule);
|
||||
let title = ''
|
||||
if (nextModule && nextModule.length > 0) {
|
||||
// `${formatMessage({ id: `menu${title.substring(0, title?.indexOf('.detail'))}` })}详情`
|
||||
title = nextModule[0].name
|
||||
}
|
||||
handleTabsPanes({ path: location?.pathname, key: location?.pathname, title: title })
|
||||
setActiveKey(location?.pathname || '')
|
||||
}
|
||||
handleTabsPanes({ path: location?.pathname, key: location?.pathname })
|
||||
}}
|
||||
>
|
||||
|
||||
@ -240,12 +337,36 @@ const BasicLayout: FC<{ user: UserModelState, global: ProfileModelState, dispatc
|
||||
<Tabs
|
||||
hideAdd
|
||||
type="editable-card"
|
||||
onChange={(value) => {
|
||||
history.push(value)
|
||||
setActiveKey(value)
|
||||
}}
|
||||
activeKey={activeKey}
|
||||
onEdit={handleEdit}
|
||||
size="small"
|
||||
className='main-tab'
|
||||
tabBarExtraContent={
|
||||
<Tooltip title="关闭选项卡" placement="topRight">
|
||||
<Dropdown overlay={
|
||||
<Menu onClick={(targetKey) => {
|
||||
let closeTabKeys: string[] = []
|
||||
switch (targetKey.key) {
|
||||
case 'other':
|
||||
closeTabKeys = [...tabsRoutes.filter(n => n.path !== activeKey).map(n => n.path)];
|
||||
break;
|
||||
case 'now':
|
||||
handleEdit(activeKey, 'remove')
|
||||
return;
|
||||
default:
|
||||
closeTabKeys = [...tabsRoutes.map(n => n.path)];
|
||||
history.push('/')
|
||||
break;
|
||||
}
|
||||
|
||||
dispatch({
|
||||
type: 'global/changeTabsRoutes',
|
||||
payload: { data: closeTabKeys, action: 'remove' },
|
||||
})
|
||||
}}>
|
||||
<Menu.Item key="other">关闭其他标签</Menu.Item>
|
||||
<Menu.Item key="now">关闭当前标签</Menu.Item>
|
||||
@ -266,7 +387,7 @@ const BasicLayout: FC<{ user: UserModelState, global: ProfileModelState, dispatc
|
||||
}
|
||||
moreIcon={<DoubleRightOutlined style={{ color: "#7b828c" }} />}
|
||||
>
|
||||
{/* {tabsPanes && tabsPanes.map((item: any) =>
|
||||
{tabsRoutes && tabsRoutes.map((item: any) =>
|
||||
<TabPane
|
||||
tab={item.title} key={item?.path}
|
||||
style={{ padding: 24, paddingTop: 0 }}>
|
||||
@ -281,7 +402,7 @@ const BasicLayout: FC<{ user: UserModelState, global: ProfileModelState, dispatc
|
||||
: <Page404 />
|
||||
}
|
||||
</TabPane>)
|
||||
} */}
|
||||
}
|
||||
</Tabs>
|
||||
|
||||
</Content>
|
||||
|
||||
@ -1,22 +1,17 @@
|
||||
// models/profile.ts
|
||||
import session from '@/utils/session';
|
||||
import { Effect, Reducer } from 'umi';
|
||||
|
||||
export interface ProfileModelState {
|
||||
avatar: string;
|
||||
bio: string;
|
||||
}
|
||||
export type ConnectState = {
|
||||
global: GlobalModelState;
|
||||
};
|
||||
|
||||
|
||||
export interface ProfileModelType {
|
||||
namespace: 'global';
|
||||
state: any;
|
||||
reducers: {
|
||||
saveTabsRoutes: Reducer<GlobalModelState>;
|
||||
};
|
||||
effects: {
|
||||
changeTabsRoutes: Effect;
|
||||
};
|
||||
}
|
||||
export type NoticeItem = {
|
||||
id: string;
|
||||
type: string;
|
||||
status: string;
|
||||
} & NoticeIconData;
|
||||
|
||||
export type tabsRoute = {
|
||||
title: string;
|
||||
@ -26,28 +21,161 @@ export type tabsRoute = {
|
||||
}
|
||||
|
||||
export type GlobalModelState = {
|
||||
collapsed: boolean;
|
||||
notices: NoticeItem[];
|
||||
tabsRoutes: tabsRoute[];
|
||||
menuData: MenuDataItem[];
|
||||
moduleMap: MenuDataItem[];
|
||||
};
|
||||
|
||||
const ProfileModel: ProfileModelType = {
|
||||
namespace: 'global',
|
||||
state: {
|
||||
tabsRoutes: [],
|
||||
},
|
||||
export type GlobalModelType = {
|
||||
namespace: 'global';
|
||||
state: GlobalModelState;
|
||||
effects: {
|
||||
fetchNotices: Effect;
|
||||
clearNotices: Effect;
|
||||
changeNoticeReadState: Effect;
|
||||
changeTabsRoutes: Effect;
|
||||
getMenuData: Effect;
|
||||
};
|
||||
reducers: {
|
||||
saveTabsRoutes(state = { tabsRoutes: [] }, { payload }): GlobalModelState {
|
||||
return {
|
||||
...state,
|
||||
tabsRoutes: payload
|
||||
changeLayoutCollapsed: Reducer<GlobalModelState>;
|
||||
saveNotices: Reducer<GlobalModelState>;
|
||||
saveClearedNotices: Reducer<GlobalModelState>;
|
||||
saveTabsRoutes: Reducer<GlobalModelState>;
|
||||
saveMenuData: Reducer<GlobalModelState>;
|
||||
saveMenuModuleMap: Reducer<GlobalModelState>;
|
||||
};
|
||||
};
|
||||
|
||||
const GlobalModel: GlobalModelType = {
|
||||
namespace: 'global',
|
||||
|
||||
state: {
|
||||
collapsed: false,
|
||||
notices: [],
|
||||
tabsRoutes: [],
|
||||
menuData: [],
|
||||
moduleMap: []
|
||||
},
|
||||
|
||||
effects: {
|
||||
*getMenuData({ payload, callback }, { put, call }) {
|
||||
const response = yield call(getUserMenu, payload);
|
||||
|
||||
const menuData = menuFormatter(response);
|
||||
// const menuData = wrapTreeNode(response);
|
||||
globalState.set('menuData', menuData);
|
||||
|
||||
yield put({
|
||||
type: 'saveMenuData',
|
||||
payload: menuData,
|
||||
});
|
||||
|
||||
yield put({
|
||||
type: 'saveMenuModuleMap',
|
||||
payload: menuFormatter(response),
|
||||
});
|
||||
if (callback && typeof callback === 'function') {
|
||||
callback(response)
|
||||
}
|
||||
},
|
||||
*fetchNotices(_, { call, put, select }) {
|
||||
|
||||
const user: CurrentUser = yield select(
|
||||
(state: ConnectState) => state.user.currentUser
|
||||
);
|
||||
const data = yield call(queryNotices, { RECSTAFF_ID: user?.ID });
|
||||
globalState.set('notices', data);
|
||||
yield put({
|
||||
type: 'saveNotices',
|
||||
payload: data,
|
||||
});
|
||||
const unreadCount: number = yield select(
|
||||
(state: ConnectState) => state.global.notices.filter((item) => item.MESSAGE_STATE === 1).length,
|
||||
);
|
||||
yield put({
|
||||
type: 'user/changeNotifyCount',
|
||||
payload: {
|
||||
totalCount: data.length,
|
||||
unreadCount,
|
||||
},
|
||||
});
|
||||
},
|
||||
*clearNotices({ payload }, { put, select, call }) {
|
||||
|
||||
const user: CurrentUser = yield select(
|
||||
(state: ConnectState) => state.user.currentUser
|
||||
);
|
||||
const notices: NoticeItem[] = yield select(
|
||||
(state: ConnectState) => state.global.notices
|
||||
);
|
||||
const clearNoticeIds = notices.reduce((p: any[], c) => {
|
||||
if (c.MESSAGE_TYPE === (payload as number)) {
|
||||
return [...p, c.MESSAGE_ID]
|
||||
}
|
||||
|
||||
return p
|
||||
}, [])
|
||||
const success = yield call(setMessageState, {
|
||||
messageIds: clearNoticeIds.toString(),
|
||||
recStaffId: user?.ID,
|
||||
messageState: 2
|
||||
}
|
||||
);
|
||||
if (success) {
|
||||
yield put({
|
||||
type: 'saveClearedNotices',
|
||||
payload,
|
||||
});
|
||||
|
||||
const count: number = yield select((state: ConnectState) => state.global.notices.length);
|
||||
const unreadCount: number = yield select(
|
||||
(state: ConnectState) => state.global.notices.filter((item) => item.MESSAGE_STATE === 1).length,
|
||||
);
|
||||
yield put({
|
||||
type: 'user/changeNotifyCount',
|
||||
payload: {
|
||||
totalCount: count,
|
||||
unreadCount,
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
* changeNoticeReadState({ payload }, { call, put, select }) {
|
||||
const notices: NoticeItem[] = yield select((state: ConnectState) =>
|
||||
state.global.notices.map((item) => {
|
||||
const notice = { ...item };
|
||||
if (notice.MESSAGE_ID === payload) {
|
||||
notice.MESSAGE_STATE = 2;
|
||||
}
|
||||
return notice;
|
||||
}),
|
||||
);
|
||||
const success = yield call(changeNoticesState, notices.find(n => n.MESSAGE_ID === payload));
|
||||
if (success) {
|
||||
yield put({
|
||||
type: 'saveNotices',
|
||||
payload: notices,
|
||||
});
|
||||
|
||||
yield put({
|
||||
type: 'user/changeNotifyCount',
|
||||
payload: {
|
||||
totalCount: notices.length,
|
||||
unreadCount: notices.filter((item) => item.MESSAGE_STATE === 1).length,
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
effects: {
|
||||
* changeTabsRoutes({ payload, callback }, { put, select }) { // 缓存路由栈
|
||||
|
||||
const tabsRoutes: tabsRoute[] = yield select((state: ConnectState) => {
|
||||
const { data } = payload
|
||||
|
||||
if (payload.action === 'add') {
|
||||
const index = state.global.tabsRoutes.findIndex(n => n.path === data.path)
|
||||
|
||||
if (index === -1) { // 没缓存 则添加
|
||||
return [...state.global.tabsRoutes, { ...data, index: state.global.tabsRoutes.length }]
|
||||
}
|
||||
@ -57,18 +185,86 @@ const ProfileModel: ProfileModelType = {
|
||||
if (payload.action === 'removeAll') {
|
||||
return []
|
||||
}
|
||||
|
||||
if (callback && typeof callback === 'function') {
|
||||
callback.call()
|
||||
}
|
||||
// 移除单个/多个路由
|
||||
return state.global.tabsRoutes.filter(n => !data.includes(n.path))
|
||||
});
|
||||
|
||||
yield put({
|
||||
type: 'saveTabsRoutes',
|
||||
payload: tabsRoutes,
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
reducers: {
|
||||
changeLayoutCollapsed(state = { notices: [], collapsed: true, tabsRoutes: [], menuData: [], moduleMap: [] }, { payload }): GlobalModelState {
|
||||
return {
|
||||
...state,
|
||||
collapsed: payload,
|
||||
};
|
||||
},
|
||||
saveNotices(state, { payload }): GlobalModelState {
|
||||
return {
|
||||
collapsed: false,
|
||||
...state,
|
||||
notices: payload,
|
||||
tabsRoutes: state?.tabsRoutes || [],
|
||||
menuData: state?.menuData || [],
|
||||
moduleMap: state?.moduleMap || []
|
||||
};
|
||||
},
|
||||
saveClearedNotices(state = { notices: [], collapsed: true, tabsRoutes: [], menuData: [], moduleMap: [] }, { payload }): GlobalModelState {
|
||||
const type = payload as number
|
||||
return {
|
||||
...state,
|
||||
collapsed: false,
|
||||
notices: state.notices.filter((item): boolean => item.MESSAGE_TYPE !== type),
|
||||
};
|
||||
},
|
||||
saveTabsRoutes(state = { notices: [], collapsed: true, tabsRoutes: [], menuData: [], moduleMap: [] }, { payload }): GlobalModelState {
|
||||
return {
|
||||
...state,
|
||||
tabsRoutes: payload
|
||||
}
|
||||
},
|
||||
saveMenuData(state = { notices: [], collapsed: true, tabsRoutes: [], menuData: [], moduleMap: [] }, { payload }): GlobalModelState {
|
||||
|
||||
return {
|
||||
...state,
|
||||
menuData: payload,
|
||||
}
|
||||
},
|
||||
saveMenuModuleMap(state = { notices: [], collapsed: true, tabsRoutes: [], menuData: [], moduleMap: [] }, { payload }): GlobalModelState { // 生成模块
|
||||
|
||||
const reduceMenu = (data: any) => {
|
||||
|
||||
return data.reduce((p: [], current: Record<string, any>) => {
|
||||
|
||||
if (current.children) {
|
||||
const d = reduceMenu(current.children)
|
||||
|
||||
return [...p, ...d]
|
||||
}
|
||||
|
||||
return [...p, current]
|
||||
}, [])
|
||||
}
|
||||
|
||||
const moduleMap = reduceMenu(payload)
|
||||
|
||||
session.set('menu', moduleMap)
|
||||
return {
|
||||
...state,
|
||||
moduleMap,
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default ProfileModel;
|
||||
export default GlobalModel;
|
||||
@ -5,7 +5,9 @@ import type { AxiosRequestHeaders } from 'axios/index';
|
||||
|
||||
const { UMI_APP_BASEURL } = process.env;
|
||||
|
||||
const instance = axios.create({ baseURL: 'https://api.eshangtech.com/EShangApiMain' });
|
||||
const instance = axios.create({ baseURL: UMI_APP_BASEURL });
|
||||
// const instance = axios.create({ baseURL: 'https://api.eshangtech.com/EShangApiMain' });
|
||||
|
||||
|
||||
instance.interceptors.request.use(
|
||||
(config) => {
|
||||
|
||||
39
src/utils/session.ts
Normal file
39
src/utils/session.ts
Normal file
@ -0,0 +1,39 @@
|
||||
const $strorage= window.sessionStorage || sessionStorage
|
||||
const session = {
|
||||
|
||||
|
||||
get: (key: string) => {
|
||||
const value = $strorage.getItem(key)
|
||||
try {
|
||||
const valueObj = JSON.parse(value);
|
||||
return valueObj;
|
||||
} catch (error) {
|
||||
return value
|
||||
}
|
||||
},
|
||||
|
||||
set: (key: string, value: any) => {
|
||||
return $strorage.setItem(key, value ? JSON.stringify(value) : value)
|
||||
},
|
||||
|
||||
remove: (key: string) => {
|
||||
return $strorage.removeItem(key)
|
||||
},
|
||||
|
||||
clearExcept: (key: string) => {
|
||||
for (let i = 0; i < $strorage.length; i+=1) {
|
||||
const itemKey: string | undefined = $strorage.key(i);
|
||||
if (itemKey && itemKey !== key) {
|
||||
$strorage.rmoveItem(itemKey);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
clearAll: () => {
|
||||
|
||||
$strorage.clear()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default session;
|
||||
Loading…
x
Reference in New Issue
Block a user