@yueglobal/ui 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,146 +1,147 @@
1
- # @yueglobal/ui
2
-
3
- 粤链全球 - React 组件库
4
-
5
- 如需`vue`版本,请前往 [@yueglobal/vue-ui](https://www.npmjs.com/package/@yueglobal/vue-ui)
6
-
7
- ## 安装使用
8
-
9
- ```shell
10
- yarn add @yueglobal/ui
11
- ```
12
-
13
- ```ts
14
- import {
15
- // 页面头部组件
16
- YuePageHeader,
17
- // 页面底部组件
18
- YuePageFooter,
19
- } from '@yueglobal/ui';
20
- ```
21
-
22
- ## YuePageHeader
23
-
24
- 页面头部组件,包含一级和二级导航菜单、面包屑、以及登录/用户信息等功能。
25
-
26
- ### 属性
27
-
28
- | 属性 | 说明 | 类型 | 默认值 |
29
- | ----------------- | ----------------------------------- | ------------------------------------------- | ------ |
30
- | `width` | 内容宽度 | `string` \| `number` | `80%` |
31
- | `backgroundColor` | 头部背景色 | `string` | `#fff` |
32
- | `rightContent` | 顶部右侧的登录/用户信息按钮 | `ReactNode` | |
33
- | `menuItems` | 各业务系统的菜单 | `YueMenuItem`[] | |
34
- | `pageTitle` | 缺值时从一级菜单取值 | `string` | |
35
- | `pageIcon` | 页面图标 | `ReactNode` | |
36
- | `breadcrumbs` | 自定义面包屑数据 | `YueBreadcrumb`[] | |
37
- | `routes` | 路由数据,用于自动生成面包屑 | any | |
38
- | `pathname` | 当前的路由 | `string` | |
39
- | `onRouteChange` | 点击菜单/面包屑时触发的路由切换事件 | `({ key: string; label?: string }) => void` | |
40
- | `onLocaleChange` | 切换语言时的回调事件 | `({locale: string}) => void` | |
41
-
42
- - 业务子系统:`pageTitle`或`pageIcon`缺省时会根据`url`自动从一级菜单匹配值
43
-
44
- - 面包屑:若`breadcrumbs`缺省,则会根据`routes`、`pathname`自动生成面包屑的数据
45
-
46
- - `routes`是`umijs`的路由列表,需按如下方式取值:
47
-
48
- ```ts
49
- import { useAppData } from '@umijs/max';
50
- // .......
51
- const { routes } = useAppData();
52
- ```
53
-
54
- ### YueMenuItem
55
-
56
- | 属性 | 说明 | 类型 | 备注 |
57
- | ---------- | ---------- | --------------- | ------------------------------ |
58
- | `key` | 唯一标识 | `string` | `必填`,可传路由地址如 `/home` |
59
- | `label` | 菜单项文案 | `string` | `必填` |
60
- | `children` | 子菜单项 | `YueMenuItem`[] | |
61
-
62
- ### YueBreadcrumb
63
-
64
- | 属性 | 说明 | 类型 | 备注 |
65
- | ------- | ---------------------- | -------- | ---------------------- |
66
- | `key` | 唯一标识,用于路由跳转 | `string` | 可传路由地址如 `/home` |
67
- | `label` | 面包屑项文案 | `string` | |
68
-
69
- ### 使用示例
70
-
71
- ```tsx | pure
72
- import React from 'react';
73
- import { YuePageHeader } from '@yueglobal/ui';
74
- import { useAppData, useLocation, useModel, history } from '@umijs/max';
75
-
76
- const Index = () => {
77
- const { routes } = useAppData();
78
- const { pathname } = useLocation();
79
- const { initialState } = useModel('@@initialState');
80
-
81
- const menuItems = [
82
- { key: '/home', label: '首页' },
83
- {
84
- key: '/exhibition',
85
- label: '展会',
86
- children: [
87
- { key: '/exhibition/international', label: '国际展会' },
88
- { key: '/exhibition/domestic', label: '国内展会' },
89
- ],
90
- },
91
- { key: '/business', label: '商务' },
92
- ];
93
-
94
- const onRouteChange = (item: { key: string; label?: string }) => {
95
- console.log('点击的菜单key: ', item.key);
96
- // 在这里处理路由跳转逻辑, 比如
97
- if (item.key.startsWith('/')) {
98
- history.push(item.key);
99
- }
100
- };
101
-
102
- const onLocaleChange = ({ locale }: { locale: string }) => {
103
- console.log('切换语言为:', locale);
104
- };
105
-
106
- return (
107
- <YuePageHeader
108
- width={1440}
109
- pageTitle="会展服务"
110
- menuItems={menuItems}
111
- pathname={pathname}
112
- routes={routes}
113
- rightContent={
114
- !!initialState?.isLogin ? <div>用户名</div> : <div>登录</div>
115
- }
116
- onRouteChange={onRouteChange}
117
- onLocaleChange={onLocaleChange}
118
- />
119
- );
120
- };
121
-
122
- export default Index;
123
- ```
124
-
125
- ## YuePageFooter
126
-
127
- 页面底部组件,显示版权信息、联系方式和相关链接。
128
-
129
- ### 属性
130
-
131
- | 属性 | 说明 | 类型 | 默认值 |
132
- | ------- | -------- | -------------------- | ------ |
133
- | `width` | 内容宽度 | `string` \| `number` | `80%` |
134
-
135
- ### 使用示例
136
-
137
- ```tsx | pure
138
- import React from 'react';
139
- import { YuePageFooter } from '@yueglobal/ui';
140
-
141
- const Index = () => {
142
- return <YuePageFooter width={1440} />;
143
- };
144
-
145
- export default Index;
146
- ```
1
+ # @yueglobal/ui
2
+
3
+ 粤链全球 - React 组件库
4
+
5
+ 如需`vue`版本,请前往 [@yueglobal/vue-ui](https://www.npmjs.com/package/@yueglobal/vue-ui)
6
+
7
+ ## 安装使用
8
+
9
+ ```shell
10
+ yarn add @yueglobal/ui
11
+ ```
12
+
13
+ ```ts
14
+ import {
15
+ // 页面头部组件
16
+ YuePageHeader,
17
+ // 页面底部组件
18
+ YuePageFooter,
19
+ } from '@yueglobal/ui';
20
+ ```
21
+
22
+ ## YuePageHeader
23
+
24
+ 页面头部组件,包含一级和二级导航菜单、面包屑、以及登录/用户信息等功能。
25
+
26
+ ### 属性
27
+
28
+ | 属性 | 说明 | 类型 | 默认值 |
29
+ | ----------------- | ----------------------------------- | ------------------------------------------- | ------ |
30
+ | `width` | 内容宽度 | `string` \| `number` | `80%` |
31
+ | `backgroundColor` | 头部背景色 | `string` | `#fff` |
32
+ | `activeLabel` | 当前选中的一级菜单项的标题 | `string` | |
33
+ | `rightContent` | 顶部右侧的登录/用户信息按钮 | `ReactNode` | |
34
+ | `menuItems` | 各业务系统的菜单 | `YueMenuItem`[] | |
35
+ | `pageTitle` | 缺值时从一级菜单取值 | `string` | |
36
+ | `pageIcon` | 页面图标 | `ReactNode` | |
37
+ | `breadcrumbs` | 自定义面包屑数据 | `YueBreadcrumb`[] | |
38
+ | `routes` | 路由数据,用于自动生成面包屑 | any | |
39
+ | `pathname` | 当前的路由 | `string` | |
40
+ | `onRouteChange` | 点击菜单/面包屑时触发的路由切换事件 | `({ key: string; label?: string }) => void` | |
41
+ | `onLocaleChange` | 切换语言时的回调事件 | `({locale: string}) => void` | |
42
+
43
+ - 业务子系统:`pageTitle`或`pageIcon`缺省时会根据`url`自动从一级菜单匹配值
44
+
45
+ - 面包屑:若`breadcrumbs`缺省,则会根据`routes`、`pathname`自动生成面包屑的数据
46
+
47
+ - `routes`是`umijs`的路由列表,需按如下方式取值:
48
+
49
+ ```ts
50
+ import { useAppData } from '@umijs/max';
51
+ // .......
52
+ const { routes } = useAppData();
53
+ ```
54
+
55
+ ### YueMenuItem
56
+
57
+ | 属性 | 说明 | 类型 | 备注 |
58
+ | ---------- | ---------- | --------------- | ------------------------------ |
59
+ | `key` | 唯一标识 | `string` | `必填`,可传路由地址如 `/home` |
60
+ | `label` | 菜单项文案 | `string` | `必填` |
61
+ | `children` | 子菜单项 | `YueMenuItem`[] | |
62
+
63
+ ### YueBreadcrumb
64
+
65
+ | 属性 | 说明 | 类型 | 备注 |
66
+ | ------- | ---------------------- | -------- | ---------------------- |
67
+ | `key` | 唯一标识,用于路由跳转 | `string` | 可传路由地址如 `/home` |
68
+ | `label` | 面包屑项文案 | `string` | |
69
+
70
+ ### 使用示例
71
+
72
+ ```tsx | pure
73
+ import React from 'react';
74
+ import { YuePageHeader } from '@yueglobal/ui';
75
+ import { useAppData, useLocation, useModel, history } from '@umijs/max';
76
+
77
+ const Index = () => {
78
+ const { routes } = useAppData();
79
+ const { pathname } = useLocation();
80
+ const { initialState } = useModel('@@initialState');
81
+
82
+ const menuItems = [
83
+ { key: '/home', label: '首页' },
84
+ {
85
+ key: '/exhibition',
86
+ label: '展会',
87
+ children: [
88
+ { key: '/exhibition/international', label: '国际展会' },
89
+ { key: '/exhibition/domestic', label: '国内展会' },
90
+ ],
91
+ },
92
+ { key: '/business', label: '商务' },
93
+ ];
94
+
95
+ const onRouteChange = (item: { key: string; label?: string }) => {
96
+ console.log('点击的菜单key: ', item.key);
97
+ // 在这里处理路由跳转逻辑, 比如
98
+ if (item.key.startsWith('/')) {
99
+ history.push(item.key);
100
+ }
101
+ };
102
+
103
+ const onLocaleChange = ({ locale }: { locale: string }) => {
104
+ console.log('切换语言为:', locale);
105
+ };
106
+
107
+ return (
108
+ <YuePageHeader
109
+ width={1440}
110
+ pageTitle="会展服务"
111
+ menuItems={menuItems}
112
+ pathname={pathname}
113
+ routes={routes}
114
+ rightContent={
115
+ !!initialState?.isLogin ? <div>用户名</div> : <div>登录</div>
116
+ }
117
+ onRouteChange={onRouteChange}
118
+ onLocaleChange={onLocaleChange}
119
+ />
120
+ );
121
+ };
122
+
123
+ export default Index;
124
+ ```
125
+
126
+ ## YuePageFooter
127
+
128
+ 页面底部组件,显示版权信息、联系方式和相关链接。
129
+
130
+ ### 属性
131
+
132
+ | 属性 | 说明 | 类型 | 默认值 |
133
+ | ------- | -------- | -------------------- | ------ |
134
+ | `width` | 内容宽度 | `string` \| `number` | `80%` |
135
+
136
+ ### 使用示例
137
+
138
+ ```tsx | pure
139
+ import React from 'react';
140
+ import { YuePageFooter } from '@yueglobal/ui';
141
+
142
+ const Index = () => {
143
+ return <YuePageFooter width={1440} />;
144
+ };
145
+
146
+ export default Index;
147
+ ```
package/package.json CHANGED
@@ -1,18 +1,18 @@
1
1
  {
2
2
  "name": "@yueglobal/ui",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "粤链全球 - react组件库",
5
5
  "license": "MIT",
6
6
  "module": "index.js",
7
7
  "typings": "index.d.ts",
8
+ "devDependencies": {
9
+ "react": "^18.0.0"
10
+ },
8
11
  "peerDependencies": {
9
12
  "antd": ">=4.23.0 || >=5.0.0",
10
13
  "react": ">=16.9.0",
11
14
  "react-dom": ">=16.9.0"
12
15
  },
13
- "devDependencies": {
14
- "react": "^18.0.0"
15
- },
16
16
  "publishConfig": {
17
17
  "access": "public"
18
18
  }
@@ -1,5 +1,12 @@
1
- import React from 'react';
1
+ import React, { ReactNode } from 'react';
2
2
  import { YuePageHeaderProps } from '../index';
3
- type Props = Pick<YuePageHeaderProps, 'breadcrumbs' | 'routes' | 'pathname' | 'onRouteChange'>;
3
+ import './index.less';
4
+ type Props = Pick<YuePageHeaderProps, 'breadcrumbs' | 'routes' | 'pathname' | 'onRouteChange'> & {
5
+ moduleData: {
6
+ title?: string;
7
+ icon?: ReactNode;
8
+ key?: string;
9
+ };
10
+ };
4
11
  declare const _default: React.NamedExoticComponent<Props>;
5
12
  export default _default;
@@ -1,18 +1,21 @@
1
- import { Breadcrumb } from 'antd';
1
+ import { Breadcrumb, Typography } from 'antd';
2
2
  import React, { memo, useMemo } from 'react';
3
3
  import { LocationIcon } from "../../components/svg-icon";
4
- import { getFullPathNodesByPath, uniqByPath } from "../helper";
4
+ import { getFullPathNodesByPath, mainHost, uniqByPath } from "../helper";
5
+ import "./index.less";
6
+ var Text = Typography.Text;
5
7
  var Index = function Index(_ref) {
6
8
  var breadcrumbs = _ref.breadcrumbs,
7
9
  routes = _ref.routes,
8
10
  pathname = _ref.pathname,
9
- onRouteChange = _ref.onRouteChange;
11
+ onRouteChange = _ref.onRouteChange,
12
+ moduleData = _ref.moduleData;
10
13
  var breadcrumbItems = useMemo(function () {
11
14
  if (breadcrumbs) {
12
15
  return breadcrumbs.map(function (item) {
13
- var _item$key;
16
+ var _item$key, _item$key2;
14
17
  return {
15
- path: (_item$key = item.key) !== null && _item$key !== void 0 && _item$key.startsWith('/') ? item.key : undefined,
18
+ path: (_item$key = item.key) !== null && _item$key !== void 0 && _item$key.startsWith('/') || (_item$key2 = item.key) !== null && _item$key2 !== void 0 && _item$key2.startsWith('http') ? item.key : undefined,
16
19
  title: item.label
17
20
  };
18
21
  });
@@ -23,14 +26,25 @@ var Index = function Index(_ref) {
23
26
  return !d.redirect && d.access !== false && !d.isLayout;
24
27
  });
25
28
  var paths = getFullPathNodesByPath(routeList, pathname);
26
- if (!paths.find(function (p) {
27
- return p.title === '首页' || p.name === '首页' || p.path === '/' || p.path === '/home';
28
- })) {
29
+ // 首页路由坐标
30
+ var homeIndex = paths.findIndex(function (p) {
31
+ var _p$title, _p$name;
32
+ return ((_p$title = p.title) === null || _p$title === void 0 ? void 0 : _p$title.startsWith('首页')) || ((_p$name = p.name) === null || _p$name === void 0 ? void 0 : _p$name.startsWith('首页')) || p.path === '/' || p.path === '/home';
33
+ });
34
+ if (homeIndex === -1) {
35
+ // 没有子项目首页的路由,添加一个
29
36
  paths.unshift({
30
- title: '首页',
37
+ title: (moduleData === null || moduleData === void 0 ? void 0 : moduleData.title) || '应用首页',
31
38
  path: '/'
32
39
  });
40
+ } else if (moduleData !== null && moduleData !== void 0 && moduleData.title) {
41
+ // 对首页重命名
42
+ paths[homeIndex].title = moduleData.title;
33
43
  }
44
+ paths.unshift({
45
+ title: '首页',
46
+ path: mainHost
47
+ });
34
48
  if ((_paths = paths) !== null && _paths !== void 0 && _paths.length) {
35
49
  paths = uniqByPath(paths);
36
50
  if (paths.length > 1) {
@@ -46,28 +60,60 @@ var Index = function Index(_ref) {
46
60
  }
47
61
  }
48
62
  return undefined;
49
- }, [breadcrumbs, routes, pathname]);
63
+ }, [breadcrumbs, routes, pathname, moduleData]);
50
64
  var itemRender = function itemRender(currentRoute, _, items, paths) {
51
- var _items;
65
+ var _paths$, _newPaths, _items;
66
+ var newPaths = paths;
67
+ var firstPath = '';
68
+ if (paths !== null && paths !== void 0 && (_paths$ = paths[0]) !== null && _paths$ !== void 0 && _paths$.startsWith('http')) {
69
+ newPaths = paths.slice(1);
70
+ firstPath = paths[0];
71
+ }
72
+ var title = currentRoute.title;
73
+ var tooltip = {
74
+ title: title,
75
+ placement: 'bottomRight'
76
+ };
77
+
78
+ // 是第一个(平台首页)
79
+ if (firstPath && !((_newPaths = newPaths) !== null && _newPaths !== void 0 && _newPaths.length)) {
80
+ return /*#__PURE__*/React.createElement("a", {
81
+ href: firstPath
82
+ }, /*#__PURE__*/React.createElement(Text, {
83
+ ellipsis: {
84
+ tooltip: tooltip
85
+ }
86
+ }, title));
87
+ }
88
+
89
+ // 其他是模块内部路由跳转
52
90
  var isLast = (currentRoute === null || currentRoute === void 0 ? void 0 : currentRoute.path) === ((_items = items[items.length - 1]) === null || _items === void 0 ? void 0 : _items.path);
53
- var fullPath = paths.join('/');
91
+ var fullPath = newPaths.join('/');
54
92
  if (!fullPath.startsWith('/')) {
55
93
  fullPath = '/' + fullPath;
56
94
  }
57
- return isLast ? /*#__PURE__*/React.createElement("span", null, currentRoute.title) : /*#__PURE__*/React.createElement("a", {
95
+ return isLast ? /*#__PURE__*/React.createElement(Text, {
96
+ ellipsis: {
97
+ tooltip: tooltip
98
+ }
99
+ }, title) : /*#__PURE__*/React.createElement("a", {
58
100
  onClick: function onClick() {
59
101
  onRouteChange === null || onRouteChange === void 0 || onRouteChange({
60
102
  key: fullPath,
61
- label: currentRoute.title
103
+ label: title
62
104
  });
63
105
  }
64
- }, currentRoute.title);
106
+ }, /*#__PURE__*/React.createElement(Text, {
107
+ ellipsis: {
108
+ tooltip: tooltip
109
+ }
110
+ }, title));
65
111
  };
66
112
  if (!(breadcrumbItems !== null && breadcrumbItems !== void 0 && breadcrumbItems.length)) {
67
113
  return null;
68
114
  }
69
115
  return /*#__PURE__*/React.createElement("div", {
70
- className: "yue-flex breadcrumb"
116
+ className: "yue-flex yue-breadcrumb"
71
117
  }, /*#__PURE__*/React.createElement(LocationIcon, {
72
118
  style: {
73
119
  fontSize: 16
@@ -0,0 +1,30 @@
1
+ .yue-breadcrumb {
2
+ gap: 12px;
3
+ padding-right: 8px;
4
+ flex-shrink: 0;
5
+
6
+ .ant-breadcrumb ol {
7
+ align-items: center;
8
+ }
9
+
10
+ .ant-breadcrumb-item,
11
+ .ant-breadcrumb-item > a {
12
+ max-width: 70px;
13
+ }
14
+
15
+ .ant-breadcrumb-item {
16
+ .ant-typography {
17
+ font-size: 12px;
18
+ color: #fff;
19
+ line-height: 1.57;
20
+ }
21
+
22
+ a {
23
+ height: max-content;
24
+
25
+ &:hover {
26
+ background-color: transparent;
27
+ }
28
+ }
29
+ }
30
+ }
@@ -1,7 +1,6 @@
1
1
  import React, { ReactNode } from 'react';
2
2
  import './index.less';
3
3
  interface Props {
4
- setVisible: (visible: boolean) => void;
5
4
  moduleData: {
6
5
  title?: string;
7
6
  icon?: ReactNode;
@@ -9,16 +9,16 @@ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len
9
9
  function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
10
10
  function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
11
11
  import { ConfigProvider, Menu } from 'antd';
12
- import React, { memo, useEffect, useState } from 'react';
13
- import { deepClone, firstMenuList, mainHost } from "../helper";
12
+ import React, { memo, useEffect, useRef, useState } from 'react';
13
+ import { deepClone, firstMenuList, mainHost, setSubMenuPopupStyle } from "../helper";
14
14
  import "./index.less";
15
15
  var Index = function Index(_ref) {
16
- var setVisible = _ref.setVisible,
17
- moduleData = _ref.moduleData;
16
+ var moduleData = _ref.moduleData;
18
17
  var _useState = useState(),
19
18
  _useState2 = _slicedToArray(_useState, 2),
20
19
  selectedKeys = _useState2[0],
21
20
  setSelectedKeys = _useState2[1];
21
+ var menuRef = useRef(null);
22
22
  var _useState3 = useState(deepClone(firstMenuList)),
23
23
  _useState4 = _slicedToArray(_useState3, 2),
24
24
  menuList = _useState4[0],
@@ -68,10 +68,8 @@ var Index = function Index(_ref) {
68
68
  return _context.abrupt("return", result === null || result === void 0 ? void 0 : result.map(function (d) {
69
69
  return {
70
70
  key: "".concat(mainHost, "/consultation/content-list?classId=").concat(d.id, "&title=").concat(d.className),
71
- label: d.className,
72
- icon: /*#__PURE__*/React.createElement("i", {
73
- className: "yue-icon-dot"
74
- })
71
+ label: d.className
72
+ // icon: <i className="yue-icon-dot" />,
75
73
  };
76
74
  }));
77
75
  case 8:
@@ -111,6 +109,18 @@ var Index = function Index(_ref) {
111
109
  window.location.href = key;
112
110
  }
113
111
  };
112
+ var onSubMenuOpen = function onSubMenuOpen(key) {
113
+ if (!menuRef.current) {
114
+ return false;
115
+ }
116
+ var index = menuList.findIndex(function (m) {
117
+ return m.key === key;
118
+ });
119
+ if (index === -1) {
120
+ return false;
121
+ }
122
+ setSubMenuPopupStyle(menuRef.current, index);
123
+ };
114
124
  return /*#__PURE__*/React.createElement(ConfigProvider, {
115
125
  theme: {
116
126
  components: {
@@ -124,14 +134,18 @@ var Index = function Index(_ref) {
124
134
  }
125
135
  }
126
136
  }, /*#__PURE__*/React.createElement(Menu, {
137
+ ref: menuRef,
127
138
  items: menuList,
128
139
  mode: "horizontal",
129
140
  rootClassName: "yue-page-header-first-menu",
130
141
  onSelect: onItem,
131
142
  onOpenChange: function onOpenChange(val) {
132
- setVisible(!!(val !== null && val !== void 0 && val.length));
143
+ if (!!(val !== null && val !== void 0 && val.length)) {
144
+ onSubMenuOpen(val[0]);
145
+ }
133
146
  },
134
147
  selectedKeys: selectedKeys
148
+ // openKeys={['home']}
135
149
  }));
136
150
  };
137
151
  export default /*#__PURE__*/memo(Index);
@@ -13,6 +13,12 @@
13
13
  display: flex;
14
14
  align-items: center;
15
15
  justify-content: center;
16
+ //max-width: 180px;
17
+ }
18
+
19
+ .ant-menu-title-content {
20
+ //white-space: wrap;
21
+ //line-height: 22px;
16
22
  }
17
23
 
18
24
  .ant-menu-submenu-title {
@@ -51,7 +57,9 @@
51
57
 
52
58
  .ant-menu-sub {
53
59
  display: flex;
60
+ align-items: center;
54
61
  justify-content: center;
62
+ flex-wrap: wrap;
55
63
  background-color: transparent;
56
64
  border-radius: 0;
57
65
  box-shadow: none;
@@ -74,6 +82,23 @@
74
82
  font-size: 20px;
75
83
  flex-shrink: 0;
76
84
  }
85
+
86
+ &:not(:has(.anticon)) {
87
+ position: relative;
88
+ padding-inline: 25px 18px;
89
+
90
+ &::before {
91
+ content: '';
92
+ position: absolute;
93
+ left: 10px;
94
+ top: 50%;
95
+ transform: translateY(-50%);
96
+ width: 4px;
97
+ height: 4px;
98
+ border-radius: 50%;
99
+ background-color: rgba(255, 255, 255, 85%);
100
+ }
101
+ }
77
102
  }
78
103
 
79
104
  .ant-menu-item-active,
@@ -1,3 +1,4 @@
1
+ import { MenuRef } from 'antd';
1
2
  import { ReactNode } from 'react';
2
3
  export interface YueMenuItem {
3
4
  key: string;
@@ -6,6 +7,7 @@ export interface YueMenuItem {
6
7
  children?: YueMenuItem[];
7
8
  request?: string;
8
9
  className?: string;
10
+ onTitleClick?: any;
9
11
  }
10
12
  export interface YueBreadcrumb {
11
13
  key?: string;
@@ -70,3 +72,9 @@ export declare function uniqByPath<T extends {
70
72
  * @returns 拷贝后的新对象或数组
71
73
  */
72
74
  export declare function deepClone<T>(obj: T): T;
75
+ /**
76
+ * 设置子菜单弹出层的样式
77
+ * @param menuRef - 菜单实例
78
+ * @param index - 子菜单索引
79
+ */
80
+ export declare function setSubMenuPopupStyle(menuRef: MenuRef, index: number): false | undefined;
@@ -18,6 +18,12 @@ export var firstMenuList = [{
18
18
  key: 'home',
19
19
  label: '出海服务',
20
20
  className: 'is-home',
21
+ onTitleClick: function onTitleClick(_ref) {
22
+ var key = _ref.key;
23
+ if (key === 'home') {
24
+ window.location.href = mainHost;
25
+ }
26
+ },
21
27
  children: [{
22
28
  key: mainHost,
23
29
  label: '首页',
@@ -58,7 +64,14 @@ export var firstMenuList = [{
58
64
  }, {
59
65
  key: "".concat(mainHost, "/#9"),
60
66
  label: '新闻资讯',
61
- request: '/api/gwtrade-plat-front/whitelist/cms-content-class/classTree?siteFlag=uce'
67
+ children: [],
68
+ request: '/api/gwtrade-plat-front/whitelist/cms-content-class/classTree?siteFlag=uce',
69
+ onTitleClick: function onTitleClick(_ref2) {
70
+ var key = _ref2.key;
71
+ if (key !== null && key !== void 0 && key.startsWith('http')) {
72
+ window.location.href = key;
73
+ }
74
+ }
62
75
  }, {
63
76
  key: "".concat(mainHost, "/#10"),
64
77
  label: '国际市场'
@@ -327,4 +340,57 @@ export function deepClone(obj) {
327
340
  }
328
341
  }
329
342
  return clonedObj;
343
+ }
344
+ function _setPopupStyle(uuid, left) {
345
+ var popupUL = window.document.getElementById(uuid);
346
+ if (popupUL) {
347
+ var contentWidth = 0;
348
+ var childLength = popupUL.children.length;
349
+ for (var i = 0; i < childLength; i++) {
350
+ var li = popupUL.children[i];
351
+ contentWidth += li.offsetWidth || 120; // 有时会读取不到值,默认给120px
352
+ }
353
+ var bodyWidth = window.document.body.clientWidth;
354
+ if (left + contentWidth > bodyWidth || contentWidth === 0 && childLength > 4) {
355
+ popupUL.style.paddingLeft = "unset";
356
+ popupUL.style.justifyContent = 'center';
357
+ } else {
358
+ popupUL.style.paddingLeft = "".concat(left - 8, "px");
359
+ popupUL.style.justifyContent = 'unset';
360
+ }
361
+ return true;
362
+ }
363
+ return false;
364
+ }
365
+
366
+ /**
367
+ * 设置子菜单弹出层的样式
368
+ * @param menuRef - 菜单实例
369
+ * @param index - 子菜单索引
370
+ */
371
+ export function setSubMenuPopupStyle(menuRef, index) {
372
+ var _menuRef$menu;
373
+ var li = menuRef === null || menuRef === void 0 || (_menuRef$menu = menuRef.menu) === null || _menuRef$menu === void 0 || (_menuRef$menu = _menuRef$menu.list) === null || _menuRef$menu === void 0 || (_menuRef$menu = _menuRef$menu.children) === null || _menuRef$menu === void 0 ? void 0 : _menuRef$menu.item(index);
374
+ if (!li) {
375
+ return false;
376
+ }
377
+ var uuid = li.getAttribute('aria-controls');
378
+ if (!uuid && li.classList.contains('ant-menu-submenu')) {
379
+ var title = li.querySelector('.ant-menu-submenu-title');
380
+ uuid = title === null || title === void 0 ? void 0 : title.getAttribute('aria-controls');
381
+ }
382
+ if (!uuid) {
383
+ return false;
384
+ }
385
+ var _li$getBoundingClient = li.getBoundingClientRect(),
386
+ left = _li$getBoundingClient.left;
387
+ setTimeout(function () {
388
+ var success = _setPopupStyle(uuid, left);
389
+ if (!success) {
390
+ setTimeout(function () {
391
+ // 重新执行一次
392
+ _setPopupStyle(uuid, left);
393
+ }, 100);
394
+ }
395
+ }, 100, uuid, left);
330
396
  }
@@ -2,6 +2,7 @@ import React, { ReactNode } from 'react';
2
2
  import { YueBreadcrumb, YueMenuItem } from './helper';
3
3
  import './index.less';
4
4
  export interface YuePageHeaderProps {
5
+ activeLabel?: string;
5
6
  width?: string | number;
6
7
  backgroundColor?: string;
7
8
  menuItems?: YueMenuItem[];
@@ -1,14 +1,8 @@
1
- var _excluded = ["width", "backgroundColor", "rightContent", "onLocaleChange", "pageTitle", "pageIcon"];
1
+ var _excluded = ["width", "backgroundColor", "rightContent", "onLocaleChange", "pageTitle", "pageIcon", "activeLabel"];
2
2
  function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
3
- function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
4
- function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
5
- function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
6
- function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
7
- function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
8
- function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
9
3
  function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
10
4
  function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
11
- import React, { memo, useMemo, useState } from 'react';
5
+ import React, { memo, useMemo } from 'react';
12
6
  import logoImg from "../assets/gw-logo.png";
13
7
  import titleImg from "../assets/ylqq-title.png";
14
8
  import FirstMenus from "./first-menus";
@@ -25,11 +19,8 @@ var Index = function Index(_ref) {
25
19
  onLocaleChange = _ref.onLocaleChange,
26
20
  pageTitle = _ref.pageTitle,
27
21
  pageIcon = _ref.pageIcon,
22
+ activeLabel = _ref.activeLabel,
28
23
  props = _objectWithoutProperties(_ref, _excluded);
29
- var _useState = useState(false),
30
- _useState2 = _slicedToArray(_useState, 2),
31
- visible = _useState2[0],
32
- setVisible = _useState2[1];
33
24
  var hasSecondMenu = useMemo(function () {
34
25
  var _props$breadcrumbs, _props$menuItems;
35
26
  return !!pageTitle || !!((_props$breadcrumbs = props.breadcrumbs) !== null && _props$breadcrumbs !== void 0 && _props$breadcrumbs.length) || !!((_props$menuItems = props.menuItems) !== null && _props$menuItems !== void 0 && _props$menuItems.length);
@@ -40,36 +31,40 @@ var Index = function Index(_ref) {
40
31
  var title = pageTitle;
41
32
  var icon = pageIcon;
42
33
  var key;
43
- if (!title || !icon) {
44
- var menuList = flattenMenuList(true);
45
- var _window$location = window.location,
46
- origin = _window$location.origin,
47
- pathname = _window$location.pathname;
48
- var url = origin + pathname;
49
- var current = menuList.find(function (m) {
50
- return !!(m !== null && m !== void 0 && m.key) && url.startsWith("".concat(m.key));
51
- });
52
- if (!current && pageTitle) {
53
- current = menuList.find(function (m) {
34
+ var firstMenuList = flattenMenuList(true);
35
+ var _window$location = window.location,
36
+ origin = _window$location.origin,
37
+ pathname = _window$location.pathname;
38
+ var url = origin + pathname;
39
+ var current = firstMenuList.find(function (m) {
40
+ return !!(m !== null && m !== void 0 && m.key) && url.startsWith("".concat(m.key));
41
+ });
42
+ if (!current) {
43
+ if (activeLabel) {
44
+ current = firstMenuList.find(function (m) {
45
+ return (m === null || m === void 0 ? void 0 : m.label) === activeLabel;
46
+ });
47
+ } else if (pageTitle) {
48
+ current = firstMenuList.find(function (m) {
54
49
  return (m === null || m === void 0 ? void 0 : m.label) === pageTitle;
55
50
  });
56
51
  }
57
- if (current) {
58
- if (!title) {
59
- title = current.label;
60
- }
61
- if (!icon) {
62
- icon = current.icon;
63
- }
64
- key = current.key;
52
+ }
53
+ if (current) {
54
+ if (!title) {
55
+ title = current.label;
56
+ }
57
+ if (!icon) {
58
+ icon = current.icon;
65
59
  }
60
+ key = current.key;
66
61
  }
67
62
  return {
68
63
  title: title,
69
64
  icon: icon,
70
65
  key: key
71
66
  };
72
- }, [pageTitle, pageIcon]);
67
+ }, [pageTitle, pageIcon, activeLabel]);
73
68
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
74
69
  style: {
75
70
  backgroundColor: backgroundColor,
@@ -101,14 +96,12 @@ var Index = function Index(_ref) {
101
96
  })), /*#__PURE__*/React.createElement("div", {
102
97
  className: "menus-bar"
103
98
  }, /*#__PURE__*/React.createElement(FirstMenus, {
104
- setVisible: setVisible,
105
99
  moduleData: moduleData
106
100
  })), /*#__PURE__*/React.createElement(RightContent, {
107
101
  content: rightContent,
108
102
  onLocaleChange: onLocaleChange
109
103
  })), hasSecondMenu && /*#__PURE__*/React.createElement(SecondMenus, _extends({
110
104
  width: width,
111
- visible: visible,
112
105
  moduleData: moduleData
113
106
  }, props))));
114
107
  };
@@ -2,7 +2,6 @@ import React, { ReactNode } from 'react';
2
2
  import { YuePageHeaderProps } from '../index';
3
3
  import './index.less';
4
4
  interface Props extends Omit<YuePageHeaderProps, 'rightContent' | 'pageTitle' | 'pageIcon'> {
5
- visible: boolean;
6
5
  moduleData: {
7
6
  title?: string;
8
7
  icon?: ReactNode;
@@ -5,9 +5,9 @@ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len
5
5
  function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
6
6
  function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
7
7
  import { ConfigProvider, Menu } from 'antd';
8
- import React, { memo, useEffect, useState } from 'react';
8
+ import React, { memo, useEffect, useRef, useState } from 'react';
9
9
  import Breadcrumb from "../breadcrumb";
10
- import { flattenTreeList } from "../helper";
10
+ import { flattenTreeList, setSubMenuPopupStyle } from "../helper";
11
11
  import "./index.less";
12
12
  var Index = function Index(_ref) {
13
13
  var width = _ref.width,
@@ -15,13 +15,13 @@ var Index = function Index(_ref) {
15
15
  routes = _ref.routes,
16
16
  menuItems = _ref.menuItems,
17
17
  pathname = _ref.pathname,
18
- visible = _ref.visible,
19
18
  moduleData = _ref.moduleData,
20
19
  onRouteChange = _ref.onRouteChange;
21
20
  var _useState = useState(),
22
21
  _useState2 = _slicedToArray(_useState, 2),
23
22
  selectedKeys = _useState2[0],
24
23
  setSelectedKeys = _useState2[1];
24
+ var menuRef = useRef(null);
25
25
  useEffect(function () {
26
26
  if (pathname) setSelectedKeys([pathname]);
27
27
  }, [pathname]);
@@ -43,8 +43,20 @@ var Index = function Index(_ref) {
43
43
  onRouteChange === null || onRouteChange === void 0 || onRouteChange(value);
44
44
  }
45
45
  };
46
+ var onSubMenuOpen = function onSubMenuOpen(key) {
47
+ if (!menuRef.current || !(menuItems !== null && menuItems !== void 0 && menuItems.length)) {
48
+ return false;
49
+ }
50
+ var index = menuItems.findIndex(function (m) {
51
+ return m.key === key;
52
+ });
53
+ if (index === -1) {
54
+ return false;
55
+ }
56
+ setSubMenuPopupStyle(menuRef.current, index);
57
+ };
46
58
  return /*#__PURE__*/React.createElement("div", {
47
- className: 'yue-page-header-second-menu' + (visible ? ' hidden' : '')
59
+ className: 'yue-page-header-second-menu'
48
60
  }, /*#__PURE__*/React.createElement("div", {
49
61
  className: "yue-flex wrapper",
50
62
  style: {
@@ -76,23 +88,28 @@ var Index = function Index(_ref) {
76
88
  className: "yue-flex module-info"
77
89
  }, !!moduleData.icon && /*#__PURE__*/React.createElement("span", {
78
90
  className: "module-icon"
79
- }, moduleData.icon), !!moduleData.title && /*#__PURE__*/React.createElement("span", {
91
+ }, moduleData.icon), !!moduleData.title && /*#__PURE__*/React.createElement("div", {
80
92
  className: "module-title"
81
93
  }, moduleData.title)), /*#__PURE__*/React.createElement("div", {
82
- className: "vr"
83
- }), /*#__PURE__*/React.createElement("div", {
84
94
  className: "menus"
85
95
  }, /*#__PURE__*/React.createElement(Menu, {
96
+ ref: menuRef,
86
97
  items: menuItems,
87
98
  mode: "horizontal",
88
99
  rootClassName: "yue-second-menu-bar",
89
100
  onSelect: onMenuClick,
90
- selectedKeys: selectedKeys
101
+ selectedKeys: selectedKeys,
102
+ onOpenChange: function onOpenChange(val) {
103
+ if (!!(val !== null && val !== void 0 && val.length)) {
104
+ onSubMenuOpen(val[0]);
105
+ }
106
+ }
91
107
  }))), /*#__PURE__*/React.createElement(Breadcrumb, {
92
108
  breadcrumbs: breadcrumbs,
93
109
  routes: routes,
94
110
  pathname: pathname,
95
- onRouteChange: onRouteChange
111
+ onRouteChange: onRouteChange,
112
+ moduleData: moduleData
96
113
  }))));
97
114
  };
98
115
  export default /*#__PURE__*/memo(Index);
@@ -17,7 +17,7 @@
17
17
  }
18
18
 
19
19
  .left {
20
- gap: 20px;
20
+ gap: 8px;
21
21
  height: 100%;
22
22
  }
23
23
 
@@ -35,6 +35,11 @@
35
35
  .module-title {
36
36
  font-size: 24px;
37
37
  font-weight: bold;
38
+ min-width: 147px;
39
+ max-width: 300px;
40
+ white-space: nowrap;
41
+ overflow: hidden;
42
+ text-overflow: ellipsis;
38
43
  }
39
44
 
40
45
  .vr {
@@ -48,23 +53,9 @@
48
53
  //max-width: 82%;
49
54
  height: 100%;
50
55
  padding-block: 1px;
51
- flex: 1 1 0%;
56
+ flex: 1 1 0;
52
57
  min-width: 0;
53
- }
54
-
55
- .breadcrumb {
56
- gap: 12px;
57
- flex-shrink: 0;
58
-
59
- a {
60
- height: max-content;
61
- color: #fff;
62
-
63
- &:hover {
64
- color: #fff;
65
- background-color: transparent;
66
- }
67
- }
58
+ padding-right: 30px;
68
59
  }
69
60
  }
70
61
 
@@ -94,6 +85,8 @@
94
85
  line-height: 32px;
95
86
  border-radius: 16px;
96
87
  padding-inline: 16px;
88
+ min-width: 80px;
89
+ text-align: center;
97
90
  }
98
91
 
99
92
  .ant-menu-submenu-active,
@@ -115,7 +108,8 @@
115
108
  left: 0 !important;
116
109
  padding: 0;
117
110
  font-size: 18px;
118
- background-color: rgba(0, 0, 0, 45%);
111
+ //background-color: rgba(0, 0, 0, 45%);
112
+ background-color: rgba(4, 41, 131, 0.65);
119
113
  border-radius: 0;
120
114
  width: 100%;
121
115
 
@@ -154,8 +148,13 @@
154
148
  }
155
149
  }
156
150
 
151
+ .ant-menu-item-active,
157
152
  .ant-menu-item-selected {
158
- background-color: rgba(0, 0, 0, 40%);
153
+ background: linear-gradient(90deg, #17f1a1, #1a4bff);
159
154
  }
155
+
156
+ /*.ant-menu-item-selected {
157
+ background-color: rgba(0, 0, 0, 40%);
158
+ }*/
160
159
  }
161
160
  }