Commit f98a9f5386dd1bc200d85b2603cad977f117d34f

Authored by 张志伟
2 parents 18552cea 06df4562

Merge remote-tracking branch 'origin/bug_fix'

src/components/GlobalHeader/AvatarDropdown.tsx
1 1 import { Avatar, Menu, Spin, message } from "antd";
2   -import { LogoutOutlined } from '@ant-design/icons';
3   -import React, { useState, useEffect } from "react";
  2 +import { LogoutOutlined } from "@ant-design/icons";
  3 +import React from "react";
4 4 import HeaderDropdown from "../HeaderDropdown";
5 5 import styles from "./index.less";
6 6 import { logoutApi } from "@/components/GlobalHeader/api";
7   -import { history, FormattedMessage } from 'umi';
  7 +import { history, FormattedMessage } from "umi";
8 8 import cookie from "js-cookie";
9   -import { getUserInfo, UserInfo } from '@/pages/Login/api';
10   -import { IMGURL } from '@/utils'
  9 +import { UserInfo } from "@/pages/Login/api";
  10 +import { IMGURL } from "@/utils";
11 11  
12 12 export interface GlobalHeaderRightProps {
13 13 menu?: boolean;
  14 + user?: UserInfo;
14 15 }
15 16  
16   -function AvatarDropdown({ menu }: GlobalHeaderRightProps) {
17   - const [currentUser, setCurrentUser] = useState<UserInfo>({});
18   - const [loading, setLoading] = useState(true);
19   -
20   - useEffect(() => {
21   - getUserInfo().then(infoRes => {
22   - setCurrentUser(infoRes.data!);
23   - setLoading(false);
24   - }).catch(e => {
25   - // history.push('/user/login');
26   - message.error(e.message);
27   - setLoading(false);
28   - });
29   - }, []);
30   -
  17 +function AvatarDropdown({ menu, user = {} }: GlobalHeaderRightProps) {
31 18 function onMenuClick(event: any) {
32   - const token = cookie.get('fw-erp');
  19 + const token = cookie.get("fw-erp");
33 20 if (!token) {
34 21 history.replace("/user/login");
35 22 return;
36 23 }
37 24 const key = event.key;
38   - if (key == 'logout') {
39   - logoutApi().then(() => {
40   - history.push('/user/login');
41   - message.success('退出登录成功!');
42   - }).catch(e => {
43   - message.error(e.message);
44   - })
  25 + if (key == "logout") {
  26 + logoutApi()
  27 + .then(() => {
  28 + history.push("/user/login");
  29 + message.success("退出登录成功!");
  30 + })
  31 + .catch((e) => {
  32 + message.error(e.message);
  33 + });
45 34 }
46 35 }
47 36  
48   - if (loading) {
49   - return <Spin size="small" style={{ marginLeft: 8, marginRight: 8 }} />;
50   - }
51   -
52 37 if (!menu) {
53 38 return (
54 39 <span className={`${styles.action} ${styles.account}`}>
55   - <Avatar
56   - size="small"
57   - className={styles.avatar}
58   - src={IMGURL.getBAvatar(currentUser.id)}
59   - alt="avatar"
60   - />
61   - <span className={styles.name}>{currentUser.name}</span>
  40 + <Avatar size="small" className={styles.avatar} src={IMGURL.getBAvatar(user?.id ?? -1)} alt="avatar" />
  41 + <span className={styles.name}>{user?.name ?? ""}</span>
62 42 </span>
63 43 );
64 44 }
65 45  
66 46 const menuHeaderDropdown = (
67   - <Menu className={styles.menu} selectedKeys={[]} onClick={onMenuClick}>
68   - <Menu.Item key="logout">
69   - <LogoutOutlined translate="yes" />
70   - <FormattedMessage id="menu.account.logout" defaultMessage="退出登录" />
71   - </Menu.Item>
72   - </Menu>
  47 + <Menu
  48 + className={styles.menu}
  49 + selectedKeys={[]}
  50 + onClick={onMenuClick}
  51 + items={[
  52 + {
  53 + label: <FormattedMessage id="menu.account.logout" defaultMessage="退出登录" />,
  54 + key: "logout",
  55 + icon: <LogoutOutlined translate="yes" />,
  56 + },
  57 + ]}
  58 + />
73 59 );
74 60  
75   - return currentUser && currentUser.name ? (
76   - <>
77   - <HeaderDropdown overlay={menuHeaderDropdown}>
78   - <span className={`${styles.action} ${styles.account}`}>
79   - <Avatar
80   - size="small"
81   - className={styles.avatar}
82   - src={IMGURL.getBAvatar(currentUser.id)}
83   - alt="avatar"
84   - />
85   - <span className={styles.name}>{currentUser.name}</span>
86   - </span>
87   - </HeaderDropdown>
88   - </>
89   - ) : (
90   - <Spin size="small" style={{ marginLeft: 8, marginRight: 8 }} />
91   - );
  61 + return (
  62 + <HeaderDropdown overlay={menuHeaderDropdown}>
  63 + <span className={`${styles.action} ${styles.account}`}>
  64 + <Avatar size="small" className={styles.avatar} src={IMGURL.getBAvatar(user?.id ?? -1)} alt="avatar" />
  65 + <span className={styles.name}>{user?.name ?? " "}</span>
  66 + </span>
  67 + </HeaderDropdown>
  68 + );
92 69 }
93 70  
94 71 export default AvatarDropdown;
... ...
src/components/GlobalHeader/RightContent.tsx
1   -import React from 'react';
  1 +import React, { useCallback, useMemo } from "react";
  2 +import { UserInfo } from "@/pages/Login/api";
  3 +import { Button, Spin } from "antd";
  4 +import Avatar from "./AvatarDropdown";
  5 +import styles from "./index.less";
  6 +import { history } from "umi";
2 7  
3   -import SelectLang from '../SelectLang';
4   -import Avatar from './AvatarDropdown';
5   -import styles from './index.less';
6   -
7   -export type SiderTheme = 'light' | 'dark';
  8 +export type SiderTheme = "light" | "dark";
8 9 export interface GlobalHeaderRightProps {
9 10 theme?: SiderTheme | "realDark" | undefined;
10 11 layout?: "side" | "top" | "mix";
  12 + user?: UserInfo;
  13 + loading?: boolean;
11 14 }
12 15  
13   -const GlobalHeaderRight: React.SFC<GlobalHeaderRightProps> = props => {
14   - const { theme, layout = "side" } = props;
  16 +const GlobalHeaderRight: React.FC<GlobalHeaderRightProps> = (props) => {
  17 + const { theme, layout = "side", user, loading } = props;
15 18 let className = styles.right;
16 19  
17 20 if (theme === "dark" && layout === "top") {
18 21 className = `${styles.right} ${styles.dark}`;
19 22 }
  23 + const report_path = useMemo(() => {
  24 + const protocol = window.location.protocol ?? "http:";
  25 + let report_url = "report.feewee.cn";
  26 + if (!PROD_APP_ENV) {
  27 + report_url = "test" + report_url;
  28 + }
  29 + report_url = protocol + "//" + report_url;
  30 + return report_url;
  31 + }, []);
20 32  
21 33 return (
22   - <div className={className}>
23   - <Avatar menu />
24   - {/* <SelectLang className={styles.action} /> */}
  34 + <div className={styles["right-ava-wrapper"]}>
  35 + <Button type="link" href={report_path} target="_blank">
  36 + 智能报表
  37 + </Button>
  38 + <Spin spinning={loading}>
  39 + <div className={className}>
  40 + <Avatar menu user={user} />
  41 + </div>
  42 + </Spin>
25 43 </div>
26 44 );
27 45 };
... ...
src/components/GlobalHeader/index.less
1   -@import '~antd/es/style/themes/default.less';
  1 +@import "~antd/es/style/themes/default.less";
2 2  
3 3 @pro-header-hover-bg: rgba(0, 0, 0, 0.025);
4 4  
... ... @@ -27,7 +27,7 @@
27 27  
28 28 .trigger {
29 29 height: @layout-header-height;
30   - padding: ~'calc((@{layout-header-height} - 20px) / 2)' 24px;
  30 + padding: ~"calc((@{layout-header-height} - 20px) / 2)" 24px;
31 31 font-size: 20px;
32 32 cursor: pointer;
33 33 transition: all 0.3s, padding 0s;
... ... @@ -42,11 +42,11 @@
42 42 overflow: hidden;
43 43 .action {
44 44 display: inline-flex;
  45 + align-items: center;
45 46 height: 100%;
46 47 padding: 0 12px;
47 48 cursor: pointer;
48 49 transition: all 0.3s;
49   - align-items: center;
50 50  
51 51 > i {
52 52 color: @text-color;
... ... @@ -67,7 +67,7 @@
67 67 }
68 68 .account {
69 69 .avatar {
70   - margin: ~'calc((@{layout-header-height} - 24px) / 2)' 0;
  70 + margin: ~"calc((@{layout-header-height} - 24px) / 2)" 0;
71 71 margin-right: 8px;
72 72 color: @primary-color;
73 73 vertical-align: top;
... ... @@ -122,39 +122,41 @@
122 122 }
123 123  
124 124 .card {
125   - height: 90px;
126   - border-radius: 4px;
127   - cursor: pointer;
128   - display: flex;
129   - justify-content: space-between;
130   - align-items: center;
131   - padding: 0 30px;
132   - background-color: #fafafa;
133   - cursor: pointer;
134   - transition: all 0.4s;
135   -
136   - &.checked, &:hover {
137   - background-color: #4190f7;
138   - color: #fff;
139   -
140   - .title, .subText {
  125 + display: flex;
  126 + align-items: center;
  127 + justify-content: space-between;
  128 + height: 90px;
  129 + padding: 0 30px;
  130 + background-color: #fafafa;
  131 + border-radius: 4px;
  132 + cursor: pointer;
  133 + cursor: pointer;
  134 + transition: all 0.4s;
  135 +
  136 + &.checked,
  137 + &:hover {
  138 + color: #fff;
  139 + background-color: #4190f7;
  140 +
  141 + .title,
  142 + .subText {
141 143 color: #fff;
142 144 }
143   -
  145 +
144 146 .check {
145 147 visibility: visible;
146 148 }
147   - }
  149 + }
148 150  
149   - & + & {
150   - margin-top: 15px;
151   - }
  151 + & + & {
  152 + margin-top: 15px;
  153 + }
152 154 }
153 155  
154 156 .title {
155 157 color: #666;
156   - font-size: 18px;
157 158 font-weight: bold;
  159 + font-size: 18px;
158 160 transition: all 0.4s;
159 161 }
160 162  
... ... @@ -165,7 +167,13 @@
165 167 }
166 168  
167 169 .check {
  170 + color: #fff;
168 171 font-size: 20px;
169 172 visibility: hidden;
170   - color: #fff;
171   -}
172 173 \ No newline at end of file
  174 +}
  175 +
  176 +.right-ava-wrapper {
  177 + display: flex;
  178 + align-items: center;
  179 + justify-content: flex-start;
  180 +}
... ...
src/layouts/BasicLayout.tsx
... ... @@ -8,6 +8,7 @@ import settings from &quot;../../config/defaultSettings&quot;;
8 8 import logo from "./images/logo.png";
9 9 import GlobalFooter from "@/components/GlobalFooter";
10 10 import { userMenuApi, MenuItem } from "./api";
  11 +import { getUserInfo, UserInfo } from "@/pages/Login/api";
11 12 import { formatMenus } from "./entity";
12 13 import zhCN from "antd/lib/locale-provider/zh_CN";
13 14 import { ConfigProvider } from "antd";
... ... @@ -28,6 +29,8 @@ export type BasicLayoutContext = { [K in &quot;location&quot;]: BasicLayoutProps[K] } &amp; {
28 29  
29 30 const BasicLayout: React.FC<BasicLayoutProps> = ({ dispatch, children, ...other }) => {
30 31 const { formatMessage } = useIntl();
  32 + const [currentUser, setCurrentUser] = useState<UserInfo>({});
  33 + const [avatarLoading, setAvatarLoading] = useState<boolean>(true);
31 34 const [collapsed, setCollapsed] = useState(false);
32 35 const [menuData, setMenuData] = useState<MenuItem[]>([]);
33 36  
... ... @@ -47,6 +50,19 @@ const BasicLayout: React.FC&lt;BasicLayoutProps&gt; = ({ dispatch, children, ...other
47 50 });
48 51 }, []);
49 52  
  53 + useEffect(() => {
  54 + setAvatarLoading(true);
  55 + getUserInfo()
  56 + .then((infoRes) => {
  57 + setCurrentUser(infoRes.data!);
  58 + setAvatarLoading(false);
  59 + })
  60 + .catch((e) => {
  61 + console.debug(e);
  62 + setAvatarLoading(false);
  63 + });
  64 + }, []);
  65 +
50 66 return (
51 67 <ConfigProvider locale={zhCN}>
52 68 <ProLayout
... ... @@ -56,7 +72,11 @@ const BasicLayout: React.FC&lt;BasicLayoutProps&gt; = ({ dispatch, children, ...other
56 72 if (menuItemProps.isUrl) {
57 73 return defaultDom;
58 74 }
59   - return <Link to={menuItemProps.path ? `${menuItemProps.path}?fp_code=${menuItemProps.code}` : ""}>{defaultDom}</Link>;
  75 + return (
  76 + <Link to={menuItemProps.path ? `${menuItemProps.path}?fp_code=${menuItemProps.code}` : ""}>
  77 + {defaultDom}
  78 + </Link>
  79 + );
60 80 }}
61 81 breadcrumbRender={(routers = []) => [
62 82 {
... ... @@ -75,13 +95,20 @@ const BasicLayout: React.FC&lt;BasicLayoutProps&gt; = ({ dispatch, children, ...other
75 95 footerRender={() => <GlobalFooter />}
76 96 menuDataRender={() => menuData as MenuDataItem[]}
77 97 formatMessage={formatMessage}
78   - rightContentRender={(rightProps) => <RightContent theme={rightProps.navTheme} layout={rightProps.layout} />}
  98 + rightContentRender={(rightProps) => (
  99 + <RightContent
  100 + user={currentUser}
  101 + loading={avatarLoading}
  102 + theme={rightProps.navTheme}
  103 + layout={rightProps.layout}
  104 + />
  105 + )}
79 106 collapsed={collapsed}
80 107 {...other}
81 108 {...settings}
82 109 navTheme={PROD_APP_ENV ? "dark" : "light"}
83 110 >
84   - <WaterMark content="霏微科技" fontSize={18}>
  111 + <WaterMark content={currentUser?.name ? `${currentUser.name} ${currentUser?.mobile ?? ""}` : ""} fontSize={18}>
85 112 {children}
86 113 </WaterMark>
87 114 </ProLayout>
... ...