mirror of https://gitee.com/topiam/eiam
⚡ 优化
parent
4c473491f5
commit
26b9a76484
|
@ -16,40 +16,50 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
import type { ActionType } from '@ant-design/pro-components';
|
import type { ActionType } from '@ant-design/pro-components';
|
||||||
import { PageContainer, ProCard, ProList } from '@ant-design/pro-components';
|
import {
|
||||||
import { Alert, App, Avatar, Badge, Card, Input, Typography } from 'antd';
|
PageContainer,
|
||||||
|
ProCard,
|
||||||
|
ProFormText,
|
||||||
|
ProList,
|
||||||
|
QueryFilter,
|
||||||
|
} from '@ant-design/pro-components';
|
||||||
|
import { App, Avatar, Badge, Card, Typography } from 'antd';
|
||||||
import React, { useRef, useState } from 'react';
|
import React, { useRef, useState } from 'react';
|
||||||
import type { AppList } from './data.d';
|
import { AppList, InitLoginType } from './data.d';
|
||||||
import { InitLoginType } from './data.d';
|
import { getAppGroupList, queryAppList } from './service';
|
||||||
import { queryAppList } from './service';
|
|
||||||
import { useIntl } from '@@/exports';
|
import { useIntl } from '@@/exports';
|
||||||
import useStyle from './style';
|
import useStyle from './style';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
|
import { useAsyncEffect } from 'ahooks';
|
||||||
|
import { SpinProps } from 'antd/es/spin';
|
||||||
|
|
||||||
const { Paragraph } = Typography;
|
const { Paragraph } = Typography;
|
||||||
const prefixCls = 'topiam-app-list';
|
const prefixCls = 'topiam-app-list';
|
||||||
|
const renderBadge = (count: number, active = false) => {
|
||||||
|
return (
|
||||||
|
<Badge
|
||||||
|
count={count}
|
||||||
|
style={{
|
||||||
|
marginBlockStart: -2,
|
||||||
|
marginInlineStart: 4,
|
||||||
|
color: active ? '#1890FF' : '#999',
|
||||||
|
backgroundColor: active ? '#E6F7FF' : '#eee',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const CardList = () => {
|
const CardList = () => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const { styles } = useStyle(prefixCls);
|
const { styles } = useStyle(prefixCls);
|
||||||
const [activeKey, setActiveKey] = useState<React.Key | undefined>('tab1');
|
// 当前组
|
||||||
|
const [currentGroup, setCurrentGroup] = useState<React.Key>();
|
||||||
const { message } = App.useApp();
|
const { message } = App.useApp();
|
||||||
const actionRef = useRef<ActionType>();
|
const actionRef = useRef<ActionType>();
|
||||||
const [searchParams, setSearchParams] = useState<{ name: string }>();
|
const [searchParams, setSearchParams] = useState<Record<string, any>>();
|
||||||
const content = (
|
const [loading, setLoading] = useState<boolean | SpinProps | undefined>(false);
|
||||||
<div style={{ textAlign: 'center' }}>
|
const [items, setItems] = useState<{ key: string; label: React.JSX.Element }[]>([]);
|
||||||
<Input.Search
|
|
||||||
placeholder={intl.formatMessage({ id: 'pages.application.search' })}
|
|
||||||
enterButton={intl.formatMessage({ id: 'pages.application.search.enter_button' })}
|
|
||||||
size="large"
|
|
||||||
style={{ maxWidth: 522, width: '100%' }}
|
|
||||||
onSearch={(value) => {
|
|
||||||
setSearchParams({ name: value });
|
|
||||||
actionRef.current?.reload();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
const initSso = (idpInitUrl: string) => {
|
const initSso = (idpInitUrl: string) => {
|
||||||
const div = window.document.createElement('div');
|
const div = window.document.createElement('div');
|
||||||
div.innerHTML =
|
div.innerHTML =
|
||||||
|
@ -64,42 +74,40 @@ const CardList = () => {
|
||||||
document.body.removeChild(div);
|
document.body.removeChild(div);
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderBadge = (count: number, active = false) => {
|
useAsyncEffect(async () => {
|
||||||
return (
|
setLoading(true);
|
||||||
<Badge
|
const { result, success } = await getAppGroupList().finally(() => {
|
||||||
count={count}
|
setLoading(false);
|
||||||
style={{
|
});
|
||||||
marginBlockStart: -2,
|
if (success && result) {
|
||||||
marginInlineStart: 4,
|
let data: { key: string; label: React.JSX.Element }[] = [];
|
||||||
color: active ? '#1890FF' : '#999',
|
result.forEach((item) => {
|
||||||
backgroundColor: active ? '#E6F7FF' : '#eee',
|
data.push({
|
||||||
}}
|
key: item.id,
|
||||||
/>
|
label: (
|
||||||
);
|
<span>
|
||||||
};
|
{item.name}
|
||||||
|
{renderBadge(item.appCount, currentGroup === item.id)}
|
||||||
|
</span>
|
||||||
|
),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
setItems(data);
|
||||||
|
// 如果有分组,取第一个分组
|
||||||
|
if (data.length > 0) {
|
||||||
|
setSearchParams({ groupId: data[0].key });
|
||||||
|
actionRef.current?.reload();
|
||||||
|
}
|
||||||
|
// 手动请求
|
||||||
|
else {
|
||||||
|
actionRef.current?.reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles}>
|
<div className={styles}>
|
||||||
<PageContainer
|
<PageContainer className={classnames(`${prefixCls}`)}>
|
||||||
className={classnames(`${prefixCls}`)}
|
|
||||||
tabList={[
|
|
||||||
{
|
|
||||||
tab: '应用列表',
|
|
||||||
key: 'list',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
tab: '应用账号',
|
|
||||||
key: 'account',
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<Alert
|
|
||||||
banner
|
|
||||||
type={'info'}
|
|
||||||
message={intl.formatMessage({ id: 'pages.application.alert' })}
|
|
||||||
showIcon
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
<ProList<AppList>
|
<ProList<AppList>
|
||||||
rowKey="id"
|
rowKey="id"
|
||||||
split
|
split
|
||||||
|
@ -111,32 +119,34 @@ const CardList = () => {
|
||||||
xl: 4,
|
xl: 4,
|
||||||
xxl: 5,
|
xxl: 5,
|
||||||
}}
|
}}
|
||||||
request={queryAppList}
|
loading={loading}
|
||||||
pagination={{}}
|
onLoadingChange={(loading) => {
|
||||||
toolbar={{
|
setLoading(loading);
|
||||||
menu: {
|
|
||||||
type: 'tab',
|
|
||||||
activeKey,
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
key: 'tab1',
|
|
||||||
label: <span>开发分组{renderBadge(99, activeKey === 'tab1')}</span>,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'tab2',
|
|
||||||
label: <span>运维分组{renderBadge(32, activeKey === 'tab2')}</span>,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
onChange(key) {
|
|
||||||
setActiveKey(key);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
}}
|
||||||
|
manualRequest
|
||||||
|
request={queryAppList}
|
||||||
|
toolbar={
|
||||||
|
items.length > 0
|
||||||
|
? {
|
||||||
|
menu: {
|
||||||
|
type: 'tab',
|
||||||
|
activeKey: currentGroup,
|
||||||
|
items: items,
|
||||||
|
onChange(key) {
|
||||||
|
if (key) {
|
||||||
|
setCurrentGroup(key);
|
||||||
|
setSearchParams((values) => {
|
||||||
|
return { ...values, groupId: key };
|
||||||
|
});
|
||||||
|
actionRef.current?.reload();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: {}
|
||||||
|
}
|
||||||
params={searchParams}
|
params={searchParams}
|
||||||
actionRef={actionRef}
|
actionRef={actionRef}
|
||||||
tableExtraRender={() => {
|
|
||||||
return <ProCard>{content}</ProCard>;
|
|
||||||
}}
|
|
||||||
renderItem={(item: AppList) => {
|
renderItem={(item: AppList) => {
|
||||||
return (
|
return (
|
||||||
item &&
|
item &&
|
||||||
|
@ -147,8 +157,11 @@ const CardList = () => {
|
||||||
hoverable
|
hoverable
|
||||||
bordered={false}
|
bordered={false}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
if (item.initLoginType === InitLoginType.PORTAL_OR_APP_INIT_SSO) {
|
if (
|
||||||
initSso(item.initLoginUrl);
|
item.initLoginType === InitLoginType.portal_or_app_init_sso &&
|
||||||
|
item?.initLoginUrl
|
||||||
|
) {
|
||||||
|
initSso(item?.initLoginUrl);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
message.warning(
|
message.warning(
|
||||||
|
@ -175,6 +188,33 @@ const CardList = () => {
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
tableExtraRender={() => {
|
||||||
|
return (
|
||||||
|
<ProCard bodyStyle={{ padding: 0 }}>
|
||||||
|
<QueryFilter
|
||||||
|
layout="horizontal"
|
||||||
|
onFinish={(values) => {
|
||||||
|
setSearchParams({ ...searchParams, ...values });
|
||||||
|
actionRef.current?.reload();
|
||||||
|
return Promise.resolve();
|
||||||
|
}}
|
||||||
|
onReset={() => {
|
||||||
|
if (items.length > 0) {
|
||||||
|
setSearchParams({ groupId: currentGroup });
|
||||||
|
} else {
|
||||||
|
setSearchParams({});
|
||||||
|
}
|
||||||
|
actionRef.current?.reload();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ProFormText
|
||||||
|
name="name"
|
||||||
|
label={intl.formatMessage({ id: 'pages.application.search.name' })}
|
||||||
|
/>
|
||||||
|
</QueryFilter>
|
||||||
|
</ProCard>
|
||||||
|
);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</PageContainer>
|
</PageContainer>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -22,8 +22,8 @@ export type AppList = {
|
||||||
template: string;
|
template: string;
|
||||||
icon?: string;
|
icon?: string;
|
||||||
name: string;
|
name: string;
|
||||||
initLoginType: InitLoginType;
|
initLoginType: InitLoginType | string;
|
||||||
initLoginUrl: string;
|
initLoginUrl?: string;
|
||||||
description: string;
|
description: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,8 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
export default {
|
export default {
|
||||||
'pages.application.search': '请输入',
|
'pages.application.search.name': '应用名称',
|
||||||
'pages.application.search.enter_button': '搜索',
|
'pages.application.tab.list': '应用列表',
|
||||||
'pages.application.alert': '请点击下方的应用进行单点登录。若希望修改应用内容,请联系管理员。',
|
'pages.application.tab.account': '应用账号',
|
||||||
'pages.application.init.warning': '仅允许应用发起',
|
'pages.application.init.warning': '仅允许应用发起',
|
||||||
};
|
};
|
||||||
|
|
|
@ -24,7 +24,6 @@ const useStyles = createStyles(({ token, css, prefixCls }, prop) => {
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: ${token.borderRadius};
|
border-radius: ${token.borderRadius};
|
||||||
.${prefixCls}-pro-table-list-toolbar-container {
|
.${prefixCls}-pro-table-list-toolbar-container {
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&-item-card {
|
&-item-card {
|
||||||
|
|
Loading…
Reference in New Issue