cfel-base-components 2.6.5 → 2.6.7
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/package.json
CHANGED
package/src/apiRequest/config.ts
CHANGED
|
@@ -10,36 +10,57 @@ instance.interceptors.request.use(
|
|
|
10
10
|
(config: any) => {
|
|
11
11
|
config.headers = {
|
|
12
12
|
...config.headers,
|
|
13
|
-
'Accept-Language': currentLanguage
|
|
13
|
+
'Accept-Language': currentLanguage
|
|
14
14
|
} as AxiosRequestHeaders
|
|
15
15
|
|
|
16
16
|
config.params = {
|
|
17
17
|
...config.params,
|
|
18
|
-
productCode: (window as any)?.g_config?.productCode
|
|
18
|
+
productCode: (window as any)?.g_config?.productCode
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
return config
|
|
22
22
|
},
|
|
23
|
-
(error: any) => Promise.reject(error)
|
|
23
|
+
(error: any) => Promise.reject(error)
|
|
24
24
|
)
|
|
25
25
|
|
|
26
26
|
instance.interceptors.response.use(
|
|
27
27
|
//状态码为2xx的时候执行
|
|
28
28
|
(response: any) => {
|
|
29
|
+
//如果返回值是blob,则直接返回
|
|
30
|
+
if (response.data instanceof Blob) {
|
|
31
|
+
return response
|
|
32
|
+
}
|
|
33
|
+
|
|
29
34
|
const { data = {} } = response
|
|
30
35
|
const { success, content, errorCode, errorMsg } = data
|
|
31
36
|
|
|
32
37
|
if (!success) {
|
|
33
38
|
notification.error({
|
|
34
|
-
message: errorMsg
|
|
39
|
+
message: errorMsg
|
|
35
40
|
})
|
|
36
|
-
return Promise.reject(
|
|
41
|
+
return Promise.reject(response)
|
|
37
42
|
}
|
|
38
43
|
|
|
39
44
|
return content
|
|
40
45
|
},
|
|
41
46
|
//状态码不为2xx的时候执行
|
|
42
47
|
(error: any) => {
|
|
48
|
+
// 如果是业务错误(在响应拦截器中已处理),直接返回
|
|
49
|
+
// 检查是否是业务错误:reject 的是 response 对象,且 success === false
|
|
50
|
+
if (error.data && error.data.success === false) {
|
|
51
|
+
// 业务错误已经在响应拦截器中显示了 errorMsg,这里直接返回
|
|
52
|
+
return Promise.reject(error)
|
|
53
|
+
}
|
|
54
|
+
// 兼容旧的判断方式
|
|
55
|
+
if (
|
|
56
|
+
error.data &&
|
|
57
|
+
error.response &&
|
|
58
|
+
error.response.status >= 200 &&
|
|
59
|
+
error.response.status < 300
|
|
60
|
+
) {
|
|
61
|
+
return Promise.reject(error)
|
|
62
|
+
}
|
|
63
|
+
|
|
43
64
|
const { response = {} } = error
|
|
44
65
|
const { status } = response
|
|
45
66
|
|
|
@@ -58,18 +79,21 @@ instance.interceptors.response.use(
|
|
|
58
79
|
'服务器发生错误,请检查服务器。' = 500,
|
|
59
80
|
'网关错误。' = 502,
|
|
60
81
|
'服务不可用,服务器暂时过载或维护。' = 503,
|
|
61
|
-
'网关超时。' = 504
|
|
82
|
+
'网关超时。' = 504
|
|
62
83
|
}
|
|
63
84
|
|
|
64
85
|
notification.error({
|
|
65
|
-
message: response?.data?.errorMsg || CodeMessage[status] || '服务暂不可用,请检查网络'
|
|
86
|
+
message: response?.data?.errorMsg || CodeMessage[status] || '服务暂不可用,请检查网络'
|
|
66
87
|
})
|
|
67
88
|
// 如果后端在非2xx响应中也返回了业务 errorCode,处理 PRODUCT_NOT_REGISTRY
|
|
68
89
|
const respData = response?.data || {}
|
|
69
|
-
if (
|
|
90
|
+
if (
|
|
91
|
+
(respData && respData.errorCode === 'PRODUCT_NOT_REGISTRY') ||
|
|
92
|
+
respData.errorCode === 'ACCESS_DENIED'
|
|
93
|
+
) {
|
|
70
94
|
if (typeof (window as any).showProductNotRegisteredOverlay === 'function') {
|
|
71
95
|
;(window as any).showProductNotRegisteredOverlay({
|
|
72
|
-
onAction: () => {}
|
|
96
|
+
onAction: () => {}
|
|
73
97
|
})
|
|
74
98
|
} else {
|
|
75
99
|
if (!(window as any).__PRODUCT_NOT_REGISTRY_SHOWN__) {
|
|
@@ -77,7 +101,7 @@ instance.interceptors.response.use(
|
|
|
77
101
|
Modal.warning({
|
|
78
102
|
title: '产品未开通',
|
|
79
103
|
content: '当前产品未开通或产品编码错误,请联系管理员或检查产品编码。',
|
|
80
|
-
okText: '知道了'
|
|
104
|
+
okText: '知道了'
|
|
81
105
|
})
|
|
82
106
|
}
|
|
83
107
|
}
|
|
@@ -86,7 +110,7 @@ instance.interceptors.response.use(
|
|
|
86
110
|
}
|
|
87
111
|
|
|
88
112
|
return Promise.reject(error)
|
|
89
|
-
}
|
|
113
|
+
}
|
|
90
114
|
)
|
|
91
115
|
|
|
92
116
|
export default instance
|
|
@@ -101,13 +125,20 @@ export function request<T = any>(config: Parameters<typeof instance.request>[0])
|
|
|
101
125
|
/**
|
|
102
126
|
* GET 请求,支持类型推断
|
|
103
127
|
*/
|
|
104
|
-
export function get<T = any>(
|
|
128
|
+
export function get<T = any>(
|
|
129
|
+
url: string,
|
|
130
|
+
config?: Omit<Parameters<typeof instance.get>[1], 'url'>
|
|
131
|
+
) {
|
|
105
132
|
return instance.get<T, T>(url, config)
|
|
106
133
|
}
|
|
107
134
|
|
|
108
135
|
/**
|
|
109
136
|
* POST 请求,支持类型推断
|
|
110
137
|
*/
|
|
111
|
-
export function post<T = any>(
|
|
138
|
+
export function post<T = any>(
|
|
139
|
+
url: string,
|
|
140
|
+
data?: any,
|
|
141
|
+
config?: Omit<Parameters<typeof instance.post>[2], 'url' | 'data'>
|
|
142
|
+
) {
|
|
112
143
|
return instance.post<T, T>(url, data, config)
|
|
113
144
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useEffect, useState } from 'react'
|
|
1
|
+
import React, { useEffect, useState, ReactNode } from 'react'
|
|
2
2
|
import { Layout, List, Menu, MenuProps, Popover } from 'antd'
|
|
3
3
|
import UserCard from './user-card'
|
|
4
4
|
import RcMenu, { SubMenu, MenuItem } from 'rc-menu'
|
|
@@ -41,6 +41,12 @@ export interface LiosLayoutlProps {
|
|
|
41
41
|
logoutUrl?: string
|
|
42
42
|
switchTenantUrl?: string
|
|
43
43
|
defaultOpenKeys?: string[]
|
|
44
|
+
/** 自定义用户信息卡片内容(将完全替换内置的 UserCard) */
|
|
45
|
+
userCard?: ReactNode
|
|
46
|
+
/** 自定义搜索输入占位文案,默认“搜索菜单...” */
|
|
47
|
+
searchPlaceholder?: string
|
|
48
|
+
/** 自定义“最近访问”标题文案,默认“最近访问” */
|
|
49
|
+
searchHistoryTitle?: string
|
|
44
50
|
isHideHeader?: boolean //是否隐藏header
|
|
45
51
|
onCollapse?: (value: boolean) => void
|
|
46
52
|
type?: string
|
|
@@ -64,6 +70,9 @@ export default function LiosLayout(props: LiosLayoutlProps) {
|
|
|
64
70
|
amountInfo,
|
|
65
71
|
myWalletInfoAction,
|
|
66
72
|
myLoginInfoAction,
|
|
73
|
+
userCard,
|
|
74
|
+
searchPlaceholder,
|
|
75
|
+
searchHistoryTitle,
|
|
67
76
|
isHideHeader,
|
|
68
77
|
onCollapse,
|
|
69
78
|
type,
|
|
@@ -273,7 +282,16 @@ export default function LiosLayout(props: LiosLayoutlProps) {
|
|
|
273
282
|
{!collapsed && <div style={{ height: 24 }}></div>}
|
|
274
283
|
|
|
275
284
|
<div style={{ width: '100%', padding: '0 16px' }}>
|
|
276
|
-
<Search
|
|
285
|
+
<Search
|
|
286
|
+
menuList={menuList}
|
|
287
|
+
collapsed={collapsed}
|
|
288
|
+
type={type || ''}
|
|
289
|
+
umiHistory={umiHistory}
|
|
290
|
+
setSelectKey={setSelectKey}
|
|
291
|
+
findKeyPath={findKeyPath}
|
|
292
|
+
searchPlaceholder={searchPlaceholder}
|
|
293
|
+
searchHistoryTitle={searchHistoryTitle}
|
|
294
|
+
/>
|
|
277
295
|
</div>
|
|
278
296
|
|
|
279
297
|
{!collapsed && <div style={{ height: 12 }}></div>}
|
|
@@ -500,7 +518,16 @@ export default function LiosLayout(props: LiosLayoutlProps) {
|
|
|
500
518
|
<Popover
|
|
501
519
|
placement="bottom"
|
|
502
520
|
content={
|
|
503
|
-
|
|
521
|
+
userCard ?? (
|
|
522
|
+
<UserCard
|
|
523
|
+
myWalletInfo={myWalletInfo}
|
|
524
|
+
MyLoginInfo={MyLoginInfo}
|
|
525
|
+
amountInfo={amountInfo}
|
|
526
|
+
customAction={customAction}
|
|
527
|
+
isCopied={isCopied}
|
|
528
|
+
copyTextToClipboard={copyTextToClipboard}
|
|
529
|
+
/>
|
|
530
|
+
)
|
|
504
531
|
}
|
|
505
532
|
arrow={false}
|
|
506
533
|
trigger="click"
|
|
@@ -556,8 +583,19 @@ type SearchProps = {
|
|
|
556
583
|
umiHistory: any
|
|
557
584
|
setSelectKey: any
|
|
558
585
|
findKeyPath: (pathname: string) => string[]
|
|
586
|
+
searchPlaceholder?: string
|
|
587
|
+
searchHistoryTitle?: string
|
|
559
588
|
}
|
|
560
|
-
function Search({
|
|
589
|
+
function Search({
|
|
590
|
+
menuList,
|
|
591
|
+
collapsed,
|
|
592
|
+
type,
|
|
593
|
+
umiHistory,
|
|
594
|
+
setSelectKey,
|
|
595
|
+
findKeyPath,
|
|
596
|
+
searchPlaceholder,
|
|
597
|
+
searchHistoryTitle,
|
|
598
|
+
}: SearchProps) {
|
|
561
599
|
useEffect(() => {
|
|
562
600
|
const handleKeyDown = (event: KeyboardEvent) => {
|
|
563
601
|
if ((navigator.platform.toLowerCase().includes('mac') ? event.metaKey : event.ctrlKey) && event.key.toLowerCase() === 'k') {
|
|
@@ -676,7 +714,7 @@ function Search({ menuList, collapsed, type, umiHistory, setSelectKey, findKeyPa
|
|
|
676
714
|
value={searchTerm}
|
|
677
715
|
onChange={(e) => handleSearch(e.target.value)}
|
|
678
716
|
className="search-input"
|
|
679
|
-
placeholder=
|
|
717
|
+
placeholder={searchPlaceholder ?? '搜索菜单...'}
|
|
680
718
|
onFocus={() => setIsFocused(true)}
|
|
681
719
|
/>
|
|
682
720
|
<div className="search-icon">
|
|
@@ -700,7 +738,7 @@ function Search({ menuList, collapsed, type, umiHistory, setSelectKey, findKeyPa
|
|
|
700
738
|
<List
|
|
701
739
|
split={false}
|
|
702
740
|
className="lists"
|
|
703
|
-
header=
|
|
741
|
+
header={searchHistoryTitle ?? '最近访问'}
|
|
704
742
|
size="small"
|
|
705
743
|
bordered
|
|
706
744
|
dataSource={searchHistory}
|
|
@@ -1,162 +1,133 @@
|
|
|
1
|
-
import React from
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
FormOutlined,
|
|
5
|
-
CopyOutlined,
|
|
6
|
-
LogoutOutlined,
|
|
7
|
-
} from "@ant-design/icons";
|
|
8
|
-
import "./index.scss";
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { SwapOutlined, CopyOutlined, LogoutOutlined } from '@ant-design/icons'
|
|
3
|
+
import './index.scss'
|
|
9
4
|
|
|
10
5
|
interface UserType {
|
|
11
|
-
name: string
|
|
12
|
-
avatar: string
|
|
13
|
-
roleInfo: any[]
|
|
14
|
-
id: string
|
|
15
|
-
account: string
|
|
16
|
-
isMaster: boolean
|
|
6
|
+
name: string
|
|
7
|
+
avatar: string
|
|
8
|
+
roleInfo: any[]
|
|
9
|
+
id: string
|
|
10
|
+
account: string
|
|
11
|
+
isMaster: boolean
|
|
17
12
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
historyAction?: any;
|
|
24
|
-
}
|
|
25
|
-
interface MyWalletInfoType {
|
|
26
|
-
availableCashAmount: string;
|
|
27
|
-
availableAmount: string;
|
|
28
|
-
currency: string;
|
|
29
|
-
}
|
|
30
|
-
interface MyLoginInfoType {
|
|
31
|
-
isAdmin: any;
|
|
13
|
+
|
|
14
|
+
export interface MyWalletInfoType {
|
|
15
|
+
availableCashAmount: string
|
|
16
|
+
availableAmount: string
|
|
17
|
+
currency: string
|
|
32
18
|
}
|
|
33
|
-
interface
|
|
34
|
-
|
|
35
|
-
currencyCode: string;
|
|
19
|
+
export interface MyLoginInfoType {
|
|
20
|
+
isAdmin: any
|
|
36
21
|
}
|
|
37
22
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
case "JPY":
|
|
45
|
-
return "JP¥ ";
|
|
46
|
-
default:
|
|
47
|
-
return "¥ ";
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
export default function UserCard({
|
|
52
|
-
myWalletInfo,
|
|
53
|
-
MyLoginInfo,
|
|
54
|
-
amountInfo,
|
|
55
|
-
customAction,
|
|
56
|
-
isCopied,
|
|
57
|
-
copyTextToClipboard,
|
|
58
|
-
}: any) {
|
|
59
|
-
const { user, tenant, custom, switchTenantUrl, logoutUrl } = (window as any)
|
|
60
|
-
?.g_config;
|
|
23
|
+
export interface UserCardProps {
|
|
24
|
+
myWalletInfo?: MyWalletInfoType
|
|
25
|
+
MyLoginInfo?: MyLoginInfoType
|
|
26
|
+
isCopied?: Record<string, boolean>
|
|
27
|
+
copyTextToClipboard?: (value: string, key: string) => void
|
|
28
|
+
}
|
|
61
29
|
|
|
62
|
-
|
|
63
|
-
|
|
30
|
+
export default function UserCard({ MyLoginInfo, isCopied, copyTextToClipboard }: UserCardProps) {
|
|
31
|
+
const { user, tenant, switchTenantUrl, logoutUrl } = (window as any)?.g_config
|
|
64
32
|
|
|
65
|
-
const {
|
|
33
|
+
const { name, avatar, roleInfo, id, account }: UserType = user || {}
|
|
66
34
|
|
|
67
|
-
const { isAdmin }: MyLoginInfoType = MyLoginInfo || {}
|
|
68
|
-
|
|
69
|
-
const { residueNum, currencyCode }: AmountInfoType = amountInfo || {};
|
|
35
|
+
const { isAdmin }: MyLoginInfoType = (MyLoginInfo || {}) as MyLoginInfoType
|
|
70
36
|
|
|
71
37
|
const UserCard = () => {
|
|
72
38
|
return (
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
39
|
+
<div className="layout-user-card">
|
|
40
|
+
<div className="user-info">
|
|
41
|
+
<div className="user-avatarBox">
|
|
42
|
+
<img className="user-avatar" src={avatar} />
|
|
43
|
+
<div className="user-mater">{isAdmin ? '主账号' : '子账号'}</div>
|
|
44
|
+
</div>
|
|
45
|
+
<div className="user-info-right">
|
|
46
|
+
<span className="name">{name}</span>
|
|
47
|
+
<div className="role-list">
|
|
48
|
+
{roleInfo?.map((i) => (
|
|
49
|
+
<span className="role-item" key={i}>
|
|
84
50
|
{i}
|
|
85
51
|
</span>
|
|
86
|
-
|
|
87
|
-
</div>
|
|
52
|
+
))}
|
|
88
53
|
</div>
|
|
89
54
|
</div>
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
onClick={() => {
|
|
97
|
-
copyTextToClipboard(id, 'id');
|
|
98
|
-
}}
|
|
99
|
-
>
|
|
100
|
-
{isCopied?.['id'] ? "已复制" : <CopyOutlined/>}
|
|
101
|
-
</div>
|
|
55
|
+
</div>
|
|
56
|
+
<div className="lios-userInfo">
|
|
57
|
+
<div className="lios-li li-flex">
|
|
58
|
+
<div className="lios-keyMare">账号ID</div>
|
|
59
|
+
<div className="lios-valueMare" title={id}>
|
|
60
|
+
{id}
|
|
102
61
|
</div>
|
|
103
|
-
<div
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
onClick={() => {
|
|
111
|
-
copyTextToClipboard(account, 'account');
|
|
112
|
-
}}
|
|
113
|
-
>
|
|
114
|
-
{isCopied?.['account'] ? "已复制" : <CopyOutlined/>}
|
|
115
|
-
</div>
|
|
62
|
+
<div
|
|
63
|
+
className={isCopied?.['id'] ? 'lios-iconDone' : 'lios-icon'}
|
|
64
|
+
onClick={() => {
|
|
65
|
+
copyTextToClipboard && copyTextToClipboard(id, 'id')
|
|
66
|
+
}}
|
|
67
|
+
>
|
|
68
|
+
{isCopied?.['id'] ? '已复制' : <CopyOutlined />}
|
|
116
69
|
</div>
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
className={isCopied?.['tenantId'] ? "lios-iconDone" : "lios-icon"}
|
|
123
|
-
onClick={() => {
|
|
124
|
-
copyTextToClipboard(tenant?.id, 'tenantId');
|
|
125
|
-
}}
|
|
126
|
-
>
|
|
127
|
-
{isCopied?.['tenantId'] ? "已复制" : <CopyOutlined/>}
|
|
128
|
-
</div>
|
|
70
|
+
</div>
|
|
71
|
+
<div className="lios-li li-flex">
|
|
72
|
+
<div className="lios-keyMare">账号</div>
|
|
73
|
+
<div className="lios-valueMare" title={account}>
|
|
74
|
+
{account}
|
|
129
75
|
</div>
|
|
130
|
-
<div
|
|
131
|
-
|
|
132
|
-
|
|
76
|
+
<div
|
|
77
|
+
className={isCopied?.['account'] ? 'lios-iconDone' : 'lios-icon'}
|
|
78
|
+
onClick={() => {
|
|
79
|
+
copyTextToClipboard && copyTextToClipboard(account, 'account')
|
|
80
|
+
}}
|
|
81
|
+
>
|
|
82
|
+
{isCopied?.['account'] ? '已复制' : <CopyOutlined />}
|
|
133
83
|
</div>
|
|
134
84
|
</div>
|
|
135
85
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
<div
|
|
139
|
-
|
|
140
|
-
onClick={() => {
|
|
141
|
-
location.href = switchTenantUrl;
|
|
142
|
-
}}
|
|
143
|
-
>
|
|
144
|
-
<SwapOutlined className="logout-icon"/>
|
|
145
|
-
切换租户
|
|
86
|
+
<div className="lios-li li-flex">
|
|
87
|
+
<div className="lios-keyMare">租户ID</div>
|
|
88
|
+
<div className="lios-valueMare" title={tenant?.id}>
|
|
89
|
+
{tenant?.id}
|
|
146
90
|
</div>
|
|
147
91
|
<div
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
92
|
+
className={isCopied?.['tenantId'] ? 'lios-iconDone' : 'lios-icon'}
|
|
93
|
+
onClick={() => {
|
|
94
|
+
copyTextToClipboard && copyTextToClipboard(tenant?.id, 'tenantId')
|
|
95
|
+
}}
|
|
152
96
|
>
|
|
153
|
-
<
|
|
154
|
-
|
|
97
|
+
{isCopied?.['tenantId'] ? '已复制' : <CopyOutlined />}
|
|
98
|
+
</div>
|
|
99
|
+
</div>
|
|
100
|
+
<div className="lios-li li-flex">
|
|
101
|
+
<div className="lios-keyMare">租户</div>
|
|
102
|
+
<div className="lios-valueMare" title={tenant?.name}>
|
|
103
|
+
{tenant?.name}
|
|
155
104
|
</div>
|
|
156
105
|
</div>
|
|
157
106
|
</div>
|
|
158
|
-
);
|
|
159
|
-
};
|
|
160
107
|
|
|
161
|
-
|
|
108
|
+
<div className="lios-logoutBox">
|
|
109
|
+
<div
|
|
110
|
+
className="lios-logout"
|
|
111
|
+
onClick={() => {
|
|
112
|
+
location.href = switchTenantUrl
|
|
113
|
+
}}
|
|
114
|
+
>
|
|
115
|
+
<SwapOutlined className="logout-icon" />
|
|
116
|
+
切换租户
|
|
117
|
+
</div>
|
|
118
|
+
<div
|
|
119
|
+
className="lios-logout"
|
|
120
|
+
onClick={() => {
|
|
121
|
+
location.href = logoutUrl
|
|
122
|
+
}}
|
|
123
|
+
>
|
|
124
|
+
<LogoutOutlined className="logout-icon" />
|
|
125
|
+
退出登录
|
|
126
|
+
</div>
|
|
127
|
+
</div>
|
|
128
|
+
</div>
|
|
129
|
+
)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return UserCard()
|
|
162
133
|
}
|