| import { LogoutOutlined, SettingOutlined, UserOutlined } from '@ant-design/icons'; |
| import { history, useModel } from '@umijs/max'; |
| import { Spin } from 'antd'; |
| import { createStyles } from 'antd-style'; |
| import { stringify } from 'querystring'; |
| import type { MenuInfo } from 'rc-menu/lib/interface'; |
| import React, { useCallback } from 'react'; |
| import { flushSync } from 'react-dom'; |
| import HeaderDropdown from '../HeaderDropdown'; |
| import { setRemoteMenu } from '@/services/session'; |
| import { clearSessionToken } from '@/access'; |
| import { logout } from '@/services/system/auth'; |
| |
| export type GlobalHeaderRightProps = { |
| menu?: boolean; |
| children?: React.ReactNode; |
| }; |
| |
| export const AvatarName = () => { |
| const { initialState } = useModel('@@initialState'); |
| const { currentUser } = initialState || {}; |
| return <span className="anticon">{currentUser?.nickName}</span>; |
| }; |
| |
| const useStyles = createStyles(({ token }) => { |
| return { |
| action: { |
| display: 'flex', |
| height: '48px', |
| marginLeft: 'auto', |
| overflow: 'hidden', |
| alignItems: 'center', |
| padding: '0 8px', |
| cursor: 'pointer', |
| borderRadius: token.borderRadius, |
| '&:hover': { |
| backgroundColor: token.colorBgTextHover, |
| }, |
| }, |
| }; |
| }); |
| |
| export const AvatarDropdown: React.FC<GlobalHeaderRightProps> = ({ menu, children }) => { |
| /** |
| * 退出登录,并且将当前的 url 保存 |
| */ |
| const loginOut = async () => { |
| await logout(); |
| clearSessionToken(); |
| setRemoteMenu(null); |
| const { search, pathname } = window.location; |
| const urlParams = new URL(window.location.href).searchParams; |
| /** 此方法会跳转到 redirect 参数所在的位置 */ |
| const redirect = urlParams.get('redirect'); |
| // Note: There may be security issues, please note |
| if (window.location.pathname !== '/user/login' && !redirect) { |
| history.replace({ |
| pathname: '/user/login', |
| search: stringify({ |
| redirect: pathname + search, |
| }), |
| }); |
| } |
| }; |
| const { styles } = useStyles(); |
| |
| const { initialState, setInitialState } = useModel('@@initialState'); |
| |
| const onMenuClick = useCallback( |
| (event: MenuInfo) => { |
| const { key } = event; |
| if (key === 'logout') { |
| flushSync(() => { |
| setInitialState((s) => ({ ...s, currentUser: undefined })); |
| }); |
| loginOut(); |
| return; |
| } |
| history.push(`/account/${key}`); |
| }, |
| [setInitialState], |
| ); |
| |
| const loading = ( |
| <span className={styles.action}> |
| <Spin |
| size="small" |
| style={{ |
| marginLeft: 8, |
| marginRight: 8, |
| }} |
| /> |
| </span> |
| ); |
| |
| if (!initialState) { |
| return loading; |
| } |
| |
| const { currentUser } = initialState; |
| |
| if (!currentUser || !currentUser.nickName) { |
| return loading; |
| } |
| |
| const menuItems = [ |
| ...(menu |
| ? [ |
| { |
| key: 'center', |
| icon: <UserOutlined />, |
| label: '个人中心', |
| }, |
| { |
| key: 'settings', |
| icon: <SettingOutlined />, |
| label: '个人设置', |
| }, |
| { |
| type: 'divider' as const, |
| }, |
| ] |
| : []), |
| { |
| key: 'logout', |
| icon: <LogoutOutlined />, |
| label: '退出登录', |
| }, |
| ]; |
| |
| return ( |
| <HeaderDropdown |
| menu={{ |
| selectedKeys: [], |
| onClick: onMenuClick, |
| items: menuItems, |
| }} |
| > |
| {children} |
| </HeaderDropdown> |
| ); |
| }; |