AvatarDropdown.tsx 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. import ModalCenter from '@/pages/Account/Center/ModalCenter';
  2. import { LogoutOutlined, SettingOutlined, UserOutlined } from '@ant-design/icons';
  3. import { useEmotionCss } from '@ant-design/use-emotion-css';
  4. import { history, useModel } from '@umijs/max';
  5. import { Spin } from 'antd';
  6. import { stringify } from 'querystring';
  7. import type { MenuInfo } from 'rc-menu/lib/interface';
  8. import React, { useCallback, useState } from 'react';
  9. import { flushSync } from 'react-dom';
  10. import HeaderDropdown from '../HeaderDropdown';
  11. export type GlobalHeaderRightProps = {
  12. menu?: boolean;
  13. children?: React.ReactNode;
  14. };
  15. export const AvatarName = () => {
  16. const { initialState } = useModel('@@initialState');
  17. const { currentUser } = initialState || {};
  18. return <span className="anticon">{currentUser?.userName}</span>;
  19. };
  20. export const AvatarDropdown: React.FC<GlobalHeaderRightProps> = ({ menu, children }) => {
  21. /**
  22. * 退出登录,并且将当前的 url 保存
  23. */
  24. const loginOut = async () => {
  25. localStorage.removeItem('Admin-Token');
  26. const { search, pathname } = window.location;
  27. const urlParams = new URL(window.location.href).searchParams;
  28. /** 此方法会跳转到 redirect 参数所在的位置 */
  29. const redirect = urlParams.get('redirect');
  30. // Note: There may be security issues, please note
  31. if (window.location.pathname !== '/user/login' && !redirect) {
  32. history.replace({
  33. pathname: '/user/login',
  34. search: stringify({
  35. redirect: pathname + search,
  36. }),
  37. });
  38. }
  39. };
  40. const actionClassName = useEmotionCss(({ token }) => {
  41. return {
  42. display: 'flex',
  43. height: '48px',
  44. marginLeft: 'auto',
  45. overflow: 'hidden',
  46. alignItems: 'center',
  47. padding: '0 8px',
  48. cursor: 'pointer',
  49. borderRadius: token.borderRadius,
  50. '&:hover': {
  51. backgroundColor: token.colorBgTextHover,
  52. },
  53. };
  54. });
  55. const { initialState, setInitialState } = useModel('@@initialState');
  56. const [visible, setVisible] = useState<boolean>(false);
  57. const onMenuClick = useCallback(
  58. (event: MenuInfo) => {
  59. const { key } = event;
  60. if (key === 'logout') {
  61. flushSync(() => {
  62. setInitialState((s) => ({ ...s, currentUser: undefined }));
  63. });
  64. loginOut();
  65. return;
  66. }
  67. if (key === 'center') {
  68. setVisible(true);
  69. return;
  70. }
  71. history.push(`/account/${key}`);
  72. },
  73. [setInitialState],
  74. );
  75. const loading = (
  76. <span className={actionClassName}>
  77. <Spin
  78. size="small"
  79. style={{
  80. marginLeft: 8,
  81. marginRight: 8,
  82. }}
  83. />
  84. </span>
  85. );
  86. if (!initialState) {
  87. return loading;
  88. }
  89. const { currentUser } = initialState;
  90. if (!currentUser || !currentUser.mobile) {
  91. return loading;
  92. }
  93. const menuItems = [
  94. ...(menu
  95. ? [
  96. {
  97. key: 'center',
  98. icon: <UserOutlined />,
  99. label: '个人中心',
  100. },
  101. {
  102. key: 'settings',
  103. icon: <SettingOutlined />,
  104. label: '个人设置',
  105. },
  106. {
  107. type: 'divider' as const,
  108. },
  109. ]
  110. : []),
  111. {
  112. key: 'center',
  113. icon: <UserOutlined />,
  114. label: '个人中心',
  115. },
  116. {
  117. key: 'logout',
  118. icon: <LogoutOutlined />,
  119. label: '退出登录',
  120. },
  121. ];
  122. return (
  123. <>
  124. {visible && <ModalCenter visible={visible} onClose={() => setVisible(false)} />}
  125. <HeaderDropdown
  126. menu={{
  127. selectedKeys: [],
  128. onClick: onMenuClick,
  129. items: menuItems,
  130. }}
  131. >
  132. {children}
  133. </HeaderDropdown>
  134. </>
  135. );
  136. };