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 = {
|
const userApi = {
|
||||||
//登录
|
//登录
|
||||||
'POST /api/user/login': async (req: Request, res: Response) => {
|
'POST /api/user/login': async (req: Request, res: Response) => {
|
||||||
console.log('req', req);
|
const { UserPassWord, UserPassport, mobile, captcha } = req.body;
|
||||||
console.log('res', res);
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
const { password, username, mobile, captcha } = req.body;
|
|
||||||
await waitTime(2000);
|
await waitTime(2000);
|
||||||
|
|
||||||
switch (true) {
|
switch (true) {
|
||||||
case username === 'admin' && password === 'ant.design':
|
case UserPassport === 'admin' && UserPassWord === 'ant.design':
|
||||||
case username === 'user' && password === 'ant.design':
|
case UserPassport === 'user' && UserPassWord === 'ant.design':
|
||||||
case /^1\d{10}$/.test(mobile) && Boolean(captcha):
|
case /^1\d{10}$/.test(mobile) && Boolean(captcha):
|
||||||
res.send(
|
res.send(
|
||||||
handleCommonRes({
|
handleCommonRes({
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
.proLayoutBox{
|
.pageLayout{
|
||||||
.ant-layout{
|
.ant-layout{
|
||||||
.ant-layout-sider{
|
.ant-layout-sider{
|
||||||
background-color: #021529;
|
background-color: #021529!important;
|
||||||
.ant-layout-sider-children{
|
.ant-layout-sider-children{
|
||||||
padding: 0;
|
padding: 0;
|
||||||
.ant-pro-sider-logo{
|
.ant-pro-sider-logo{
|
||||||
@ -13,7 +13,7 @@
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
line-height: 32px;
|
// line-height: 32px;
|
||||||
vertical-align: none;
|
vertical-align: none;
|
||||||
margin-left: 12px;
|
margin-left: 12px;
|
||||||
}
|
}
|
||||||
@ -22,9 +22,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.ant-layout-sider-children{
|
.ant-layout-sider-children{
|
||||||
.ant-pro-sider-extra{
|
|
||||||
margin: 0;
|
|
||||||
.ant-layout{
|
|
||||||
ul{
|
ul{
|
||||||
li{
|
li{
|
||||||
span{
|
span{
|
||||||
@ -40,8 +37,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -53,4 +48,165 @@
|
|||||||
padding: 0;
|
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 { useState, useEffect } from 'react';
|
||||||
import { Dropdown, Layout, Menu, Tabs, Tooltip } from 'antd';
|
import { Dropdown, Layout, Menu, Tabs, Tooltip } from 'antd';
|
||||||
import type { MenuProps } 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 PageAccess from '@/components/PageAccess';
|
||||||
import type { UserConnectedProps, UserModelState } from '@/models/user';
|
import type { UserConnectedProps, UserModelState } from '@/models/user';
|
||||||
import LayoutWrapper from '@/components/LayoutWrapper';
|
import LayoutWrapper from '@/components/LayoutWrapper';
|
||||||
@ -18,6 +18,8 @@ import { ProfileModelState } from '@/models/global';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
const { Header, Content } = Layout;
|
const { Header, Content } = Layout;
|
||||||
|
const { TabPane } = Tabs;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取openKeys的方法
|
* 获取openKeys的方法
|
||||||
* @param currentLocation 当前位置, 由handleGetCurrentLocation方法返回
|
* @param currentLocation 当前位置, 由handleGetCurrentLocation方法返回
|
||||||
@ -43,7 +45,7 @@ const handleGetOpenKeys = (currentLocation: API.MenuItem[] | []): string[] => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
//自定义的layout页面, 顶部导航通栏+侧边栏(菜单)布局, 可根据需要做调整
|
//自定义的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 [collapsed, setCollapsed] = useState(false);
|
||||||
const [openKeys, setOpenKeys] = useState(['']);
|
const [openKeys, setOpenKeys] = useState(['']);
|
||||||
const { pathname } = useLocation();
|
const { pathname } = useLocation();
|
||||||
@ -54,11 +56,12 @@ const BasicLayout: FC<{ user: UserModelState, global: ProfileModelState, dispatc
|
|||||||
indexValidMenuItemByPath
|
indexValidMenuItemByPath
|
||||||
},
|
},
|
||||||
global: {
|
global: {
|
||||||
|
tabsRoutes
|
||||||
}
|
}
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
console.log('props', props);
|
console.log('props', props);
|
||||||
|
const [activeKey, setActiveKey] = useState<string>('/')
|
||||||
|
|
||||||
|
|
||||||
const validMenuItem = indexValidMenuItemByPath[pathname];
|
const validMenuItem = indexValidMenuItemByPath[pathname];
|
||||||
@ -140,17 +143,103 @@ const BasicLayout: FC<{ user: UserModelState, global: ProfileModelState, dispatc
|
|||||||
// 改变panes
|
// 改变panes
|
||||||
const handleTabsPanes = (payload: any): void => {
|
const handleTabsPanes = (payload: any): void => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "global/saveTabsRoutes",
|
type: 'global/changeTabsRoutes',
|
||||||
payload: {
|
payload: { data: payload, action: 'add' },
|
||||||
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 (
|
return (
|
||||||
<LayoutWrapper>
|
<LayoutWrapper>
|
||||||
<ProLayout
|
<ProLayout
|
||||||
|
className={"pageLayout"}
|
||||||
logo={logo}
|
logo={logo}
|
||||||
contentWidth={"Fluid"}
|
contentWidth={"Fluid"}
|
||||||
fixedHeader={true}
|
fixedHeader={true}
|
||||||
@ -206,11 +295,19 @@ const BasicLayout: FC<{ user: UserModelState, global: ProfileModelState, dispatc
|
|||||||
onPageChange={(location) => {
|
onPageChange={(location) => {
|
||||||
console.log('location', location);
|
console.log('location', location);
|
||||||
if (location?.pathname && location?.pathname !== '/') {
|
if (location?.pathname && location?.pathname !== '/') {
|
||||||
const nextModule = consumableMenu.find(n => location?.pathname && n?.path && location?.pathname.match(n?.path))
|
console.log('oneFloorList', oneFloorList);
|
||||||
console.log('nextModule', nextModule);
|
|
||||||
|
|
||||||
|
// 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
|
<Tabs
|
||||||
hideAdd
|
hideAdd
|
||||||
type="editable-card"
|
type="editable-card"
|
||||||
|
onChange={(value) => {
|
||||||
|
history.push(value)
|
||||||
|
setActiveKey(value)
|
||||||
|
}}
|
||||||
|
activeKey={activeKey}
|
||||||
|
onEdit={handleEdit}
|
||||||
size="small"
|
size="small"
|
||||||
className='main-tab'
|
className='main-tab'
|
||||||
tabBarExtraContent={
|
tabBarExtraContent={
|
||||||
<Tooltip title="关闭选项卡" placement="topRight">
|
<Tooltip title="关闭选项卡" placement="topRight">
|
||||||
<Dropdown overlay={
|
<Dropdown overlay={
|
||||||
<Menu onClick={(targetKey) => {
|
<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="other">关闭其他标签</Menu.Item>
|
||||||
<Menu.Item key="now">关闭当前标签</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" }} />}
|
moreIcon={<DoubleRightOutlined style={{ color: "#7b828c" }} />}
|
||||||
>
|
>
|
||||||
{/* {tabsPanes && tabsPanes.map((item: any) =>
|
{tabsRoutes && tabsRoutes.map((item: any) =>
|
||||||
<TabPane
|
<TabPane
|
||||||
tab={item.title} key={item?.path}
|
tab={item.title} key={item?.path}
|
||||||
style={{ padding: 24, paddingTop: 0 }}>
|
style={{ padding: 24, paddingTop: 0 }}>
|
||||||
@ -281,7 +402,7 @@ const BasicLayout: FC<{ user: UserModelState, global: ProfileModelState, dispatc
|
|||||||
: <Page404 />
|
: <Page404 />
|
||||||
}
|
}
|
||||||
</TabPane>)
|
</TabPane>)
|
||||||
} */}
|
}
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
</Content>
|
</Content>
|
||||||
|
|||||||
@ -1,22 +1,17 @@
|
|||||||
// models/profile.ts
|
// models/profile.ts
|
||||||
|
import session from '@/utils/session';
|
||||||
import { Effect, Reducer } from 'umi';
|
import { Effect, Reducer } from 'umi';
|
||||||
|
|
||||||
export interface ProfileModelState {
|
export type ConnectState = {
|
||||||
avatar: string;
|
global: GlobalModelState;
|
||||||
bio: string;
|
};
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export interface ProfileModelType {
|
export type NoticeItem = {
|
||||||
namespace: 'global';
|
id: string;
|
||||||
state: any;
|
type: string;
|
||||||
reducers: {
|
status: string;
|
||||||
saveTabsRoutes: Reducer<GlobalModelState>;
|
} & NoticeIconData;
|
||||||
};
|
|
||||||
effects: {
|
|
||||||
changeTabsRoutes: Effect;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export type tabsRoute = {
|
export type tabsRoute = {
|
||||||
title: string;
|
title: string;
|
||||||
@ -26,28 +21,161 @@ export type tabsRoute = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type GlobalModelState = {
|
export type GlobalModelState = {
|
||||||
|
collapsed: boolean;
|
||||||
|
notices: NoticeItem[];
|
||||||
tabsRoutes: tabsRoute[];
|
tabsRoutes: tabsRoute[];
|
||||||
|
menuData: MenuDataItem[];
|
||||||
|
moduleMap: MenuDataItem[];
|
||||||
};
|
};
|
||||||
|
|
||||||
const ProfileModel: ProfileModelType = {
|
export type GlobalModelType = {
|
||||||
namespace: 'global',
|
namespace: 'global';
|
||||||
state: {
|
state: GlobalModelState;
|
||||||
tabsRoutes: [],
|
effects: {
|
||||||
},
|
fetchNotices: Effect;
|
||||||
|
clearNotices: Effect;
|
||||||
|
changeNoticeReadState: Effect;
|
||||||
|
changeTabsRoutes: Effect;
|
||||||
|
getMenuData: Effect;
|
||||||
|
};
|
||||||
reducers: {
|
reducers: {
|
||||||
saveTabsRoutes(state = { tabsRoutes: [] }, { payload }): GlobalModelState {
|
changeLayoutCollapsed: Reducer<GlobalModelState>;
|
||||||
return {
|
saveNotices: Reducer<GlobalModelState>;
|
||||||
...state,
|
saveClearedNotices: Reducer<GlobalModelState>;
|
||||||
tabsRoutes: payload
|
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 }) { // 缓存路由栈
|
* changeTabsRoutes({ payload, callback }, { put, select }) { // 缓存路由栈
|
||||||
|
|
||||||
const tabsRoutes: tabsRoute[] = yield select((state: ConnectState) => {
|
const tabsRoutes: tabsRoute[] = yield select((state: ConnectState) => {
|
||||||
const { data } = payload
|
const { data } = payload
|
||||||
|
|
||||||
if (payload.action === 'add') {
|
if (payload.action === 'add') {
|
||||||
const index = state.global.tabsRoutes.findIndex(n => n.path === data.path)
|
const index = state.global.tabsRoutes.findIndex(n => n.path === data.path)
|
||||||
|
|
||||||
if (index === -1) { // 没缓存 则添加
|
if (index === -1) { // 没缓存 则添加
|
||||||
return [...state.global.tabsRoutes, { ...data, index: state.global.tabsRoutes.length }]
|
return [...state.global.tabsRoutes, { ...data, index: state.global.tabsRoutes.length }]
|
||||||
}
|
}
|
||||||
@ -57,18 +185,86 @@ const ProfileModel: ProfileModelType = {
|
|||||||
if (payload.action === 'removeAll') {
|
if (payload.action === 'removeAll') {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
if (callback && typeof callback === 'function') {
|
if (callback && typeof callback === 'function') {
|
||||||
callback.call()
|
callback.call()
|
||||||
}
|
}
|
||||||
// 移除单个/多个路由
|
// 移除单个/多个路由
|
||||||
return state.global.tabsRoutes.filter(n => !data.includes(n.path))
|
return state.global.tabsRoutes.filter(n => !data.includes(n.path))
|
||||||
});
|
});
|
||||||
|
|
||||||
yield put({
|
yield put({
|
||||||
type: 'saveTabsRoutes',
|
type: 'saveTabsRoutes',
|
||||||
payload: tabsRoutes,
|
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 { 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(
|
instance.interceptors.request.use(
|
||||||
(config) => {
|
(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