diff --git a/eiam-application/eiam-application-core/src/main/java/cn/topiam/employee/application/ApplicationService.java b/eiam-application/eiam-application-core/src/main/java/cn/topiam/employee/application/ApplicationService.java index e4f2c028..47ba8a7d 100644 --- a/eiam-application/eiam-application-core/src/main/java/cn/topiam/employee/application/ApplicationService.java +++ b/eiam-application/eiam-application-core/src/main/java/cn/topiam/employee/application/ApplicationService.java @@ -17,6 +17,7 @@ */ package cn.topiam.employee.application; +import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -86,6 +87,19 @@ public interface ApplicationService { */ String getBase64Icon(); + /** + * 创建应用 + * + * @param name {@link String} 名称 + * @param icon {@link String} 图标 + * @param remark {@link String} 备注 + * @return {@link Long} 应用ID + */ + @Transactional(rollbackFor = Exception.class) + default String create(String name, String icon, String remark) { + return create(name, icon, remark, new ArrayList<>()); + } + /** * 创建应用 * diff --git a/eiam-common/src/main/java/cn/topiam/employee/common/repository/app/impl/AppRepositoryCustomizedImpl.java b/eiam-common/src/main/java/cn/topiam/employee/common/repository/app/impl/AppRepositoryCustomizedImpl.java index 595f6909..be64b691 100644 --- a/eiam-common/src/main/java/cn/topiam/employee/common/repository/app/impl/AppRepositoryCustomizedImpl.java +++ b/eiam-common/src/main/java/cn/topiam/employee/common/repository/app/impl/AppRepositoryCustomizedImpl.java @@ -119,7 +119,7 @@ public class AppRepositoryCustomizedImpl implements AppRepositoryCustomized { */ public Page getAppList(AppQuery appQuery, Pageable pageable) { //@formatter:off - StringBuilder builder = new StringBuilder("SELECT DISTINCT app.* FROM app INNER JOIN app_group_association `group` ON app.id_ = `group`.app_id AND app.is_deleted = 0"); + StringBuilder builder = new StringBuilder("SELECT DISTINCT app.* FROM app LEFT JOIN app_group_association `group` ON app.id_ = `group`.app_id AND app.is_deleted = 0"); //应用名称 if (StringUtils.isNoneBlank(appQuery.getName())) { diff --git a/eiam-console/src/main/console-fe/src/pages/authn/IdentityProvider/IdentityProvider.tsx b/eiam-console/src/main/console-fe/src/pages/authn/IdentityProvider/IdentityProvider.tsx index 875275eb..61463414 100644 --- a/eiam-console/src/main/console-fe/src/pages/authn/IdentityProvider/IdentityProvider.tsx +++ b/eiam-console/src/main/console-fe/src/pages/authn/IdentityProvider/IdentityProvider.tsx @@ -361,7 +361,7 @@ const IdentityProvider = () => { const { styles } = useStyle(prefixCls); useMount(async () => { - if (!type || !(type.toUpperCase() in IdentityProviderCategory)) { + if (!type || !IdentityProviderCategory[type]) { setTabActiveKey(IdentityProviderCategory.social); history.push({ pathname: location.pathname, diff --git a/eiam-console/src/main/java/cn/topiam/employee/console/service/app/impl/AppServiceImpl.java b/eiam-console/src/main/java/cn/topiam/employee/console/service/app/impl/AppServiceImpl.java index b4ee356e..06087afe 100644 --- a/eiam-console/src/main/java/cn/topiam/employee/console/service/app/impl/AppServiceImpl.java +++ b/eiam-console/src/main/java/cn/topiam/employee/console/service/app/impl/AppServiceImpl.java @@ -17,10 +17,7 @@ */ package cn.topiam.employee.console.service.app.impl; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Optional; +import java.util.*; import cn.topiam.employee.common.entity.app.AppGroupAssociationEntity; import cn.topiam.employee.common.repository.app.AppGroupAssociationRepository; @@ -52,6 +49,7 @@ import cn.topiam.employee.support.util.BeanUtils; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.util.CollectionUtils; import static cn.topiam.employee.support.repository.domain.BaseEntity.LAST_MODIFIED_BY; import static cn.topiam.employee.support.repository.domain.BaseEntity.LAST_MODIFIED_TIME; @@ -78,7 +76,7 @@ public class AppServiceImpl implements AppService { public Page getAppList(PageModel pageModel, AppQuery query) { //查询映射 org.springframework.data.domain.Page list = appRepository.getAppList(query, - PageRequest.of(pageModel.getCurrent(), pageModel.getPageSize())); + PageRequest.of(pageModel.getCurrent(), pageModel.getPageSize())); return appConverter.entityConvertToAppListResult(list); } @@ -92,9 +90,14 @@ public class AppServiceImpl implements AppService { @Transactional(rollbackFor = Exception.class) public AppCreateResult createApp(AppCreateParam param) { ApplicationService applicationService = applicationServiceLoader - .getApplicationService(param.getTemplate()); - String appId = applicationService.create(param.getName(), param.getIcon(), - param.getRemark(), param.getGroupIds()); + .getApplicationService(param.getTemplate()); + String appId; + if (!CollectionUtils.isEmpty(param.getGroupIds())) { + appId = applicationService.create(param.getName(), param.getIcon(), param.getRemark(), + param.getGroupIds()); + } else { + appId = applicationService.create(param.getName(), param.getIcon(), param.getRemark()); + } AuditContext.setTarget(Target.builder().id(appId).type(TargetType.APPLICATION).build()); return new AppCreateResult(appId); } @@ -122,7 +125,7 @@ public class AppServiceImpl implements AppService { } appGroupAssociationRepository.saveAll(list); AuditContext.setTarget( - Target.builder().id(param.getId().toString()).type(TargetType.APPLICATION).build()); + Target.builder().id(param.getId().toString()).type(TargetType.APPLICATION).build()); return true; } @@ -139,7 +142,7 @@ public class AppServiceImpl implements AppService { applicationServiceLoader.getApplicationService(app.getTemplate()).delete(id.toString()); appGroupAssociationRepository.deleteAllByAppId(id); AuditContext - .setTarget(Target.builder().id(id.toString()).type(TargetType.APPLICATION).build()); + .setTarget(Target.builder().id(id.toString()).type(TargetType.APPLICATION).build()); return true; } @@ -198,10 +201,10 @@ public class AppServiceImpl implements AppService { @Override public Boolean saveAppConfig(AppSaveConfigParam param) { ApplicationService applicationService = applicationServiceLoader - .getApplicationService(param.getTemplate()); + .getApplicationService(param.getTemplate()); applicationService.saveConfig(param.getId(), param.getConfig()); AuditContext - .setTarget(Target.builder().id(param.getId()).type(TargetType.APPLICATION).build()); + .setTarget(Target.builder().id(param.getId()).type(TargetType.APPLICATION).build()); return true; } @@ -216,7 +219,7 @@ public class AppServiceImpl implements AppService { Optional optional = appRepository.findById(Long.valueOf(appId)); if (optional.isPresent()) { ApplicationService applicationService = applicationServiceLoader - .getApplicationService(optional.get().getTemplate()); + .getApplicationService(optional.get().getTemplate()); return applicationService.getConfig(appId); } throw new AppNotExistException(); @@ -241,17 +244,17 @@ public class AppServiceImpl implements AppService { /** * ApplicationTemplateLoader */ - private final ApplicationServiceLoader applicationServiceLoader; + private final ApplicationServiceLoader applicationServiceLoader; /** * ApplicationRepository */ - private final AppRepository appRepository; + private final AppRepository appRepository; /** * ApplicationConverter */ - private final AppConverter appConverter; + private final AppConverter appConverter; /** * AppGroupAssociationRepositorys diff --git a/eiam-portal/src/main/portal-fe/src/pages/Application/Application.tsx b/eiam-portal/src/main/portal-fe/src/pages/Application/Application.tsx index 2f0e22ad..892bd3c4 100644 --- a/eiam-portal/src/main/portal-fe/src/pages/Application/Application.tsx +++ b/eiam-portal/src/main/portal-fe/src/pages/Application/Application.tsx @@ -16,40 +16,50 @@ * along with this program. If not, see . */ import type { ActionType } from '@ant-design/pro-components'; -import { PageContainer, ProCard, ProList } from '@ant-design/pro-components'; -import { Alert, App, Avatar, Badge, Card, Input, Typography } from 'antd'; +import { + 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 type { AppList } from './data.d'; -import { InitLoginType } from './data.d'; -import { queryAppList } from './service'; +import { AppList, InitLoginType } from './data.d'; +import { getAppGroupList, queryAppList } from './service'; import { useIntl } from '@@/exports'; import useStyle from './style'; import classnames from 'classnames'; +import { useAsyncEffect } from 'ahooks'; +import { SpinProps } from 'antd/es/spin'; + const { Paragraph } = Typography; const prefixCls = 'topiam-app-list'; +const renderBadge = (count: number, active = false) => { + return ( + + ); +}; const CardList = () => { const intl = useIntl(); const { styles } = useStyle(prefixCls); - const [activeKey, setActiveKey] = useState('tab1'); - + // 当前组 + const [currentGroup, setCurrentGroup] = useState(); const { message } = App.useApp(); const actionRef = useRef(); - const [searchParams, setSearchParams] = useState<{ name: string }>(); - const content = ( -
- { - setSearchParams({ name: value }); - actionRef.current?.reload(); - }} - /> -
- ); + const [searchParams, setSearchParams] = useState>(); + const [loading, setLoading] = useState(false); + const [items, setItems] = useState<{ key: string; label: React.JSX.Element }[]>([]); + const initSso = (idpInitUrl: string) => { const div = window.document.createElement('div'); div.innerHTML = @@ -64,42 +74,40 @@ const CardList = () => { document.body.removeChild(div); }; - const renderBadge = (count: number, active = false) => { - return ( - - ); - }; + useAsyncEffect(async () => { + setLoading(true); + const { result, success } = await getAppGroupList().finally(() => { + setLoading(false); + }); + if (success && result) { + let data: { key: string; label: React.JSX.Element }[] = []; + result.forEach((item) => { + data.push({ + key: item.id, + label: ( + + {item.name} + {renderBadge(item.appCount, currentGroup === item.id)} + + ), + }); + }); + setItems(data); + // 如果有分组,取第一个分组 + if (data.length > 0) { + setSearchParams({ groupId: data[0].key }); + actionRef.current?.reload(); + } + // 手动请求 + else { + actionRef.current?.reload(); + } + } + }, []); return (
- - -
+ rowKey="id" split @@ -111,32 +119,34 @@ const CardList = () => { xl: 4, xxl: 5, }} - request={queryAppList} - pagination={{}} - toolbar={{ - menu: { - type: 'tab', - activeKey, - items: [ - { - key: 'tab1', - label: 开发分组{renderBadge(99, activeKey === 'tab1')}, - }, - { - key: 'tab2', - label: 运维分组{renderBadge(32, activeKey === 'tab2')}, - }, - ], - onChange(key) { - setActiveKey(key); - }, - }, + loading={loading} + onLoadingChange={(loading) => { + setLoading(loading); }} + 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} actionRef={actionRef} - tableExtraRender={() => { - return {content}; - }} renderItem={(item: AppList) => { return ( item && @@ -147,8 +157,11 @@ const CardList = () => { hoverable bordered={false} onClick={async () => { - if (item.initLoginType === InitLoginType.PORTAL_OR_APP_INIT_SSO) { - initSso(item.initLoginUrl); + if ( + item.initLoginType === InitLoginType.portal_or_app_init_sso && + item?.initLoginUrl + ) { + initSso(item?.initLoginUrl); return; } message.warning( @@ -175,6 +188,33 @@ const CardList = () => { ) ); }} + tableExtraRender={() => { + return ( + + { + setSearchParams({ ...searchParams, ...values }); + actionRef.current?.reload(); + return Promise.resolve(); + }} + onReset={() => { + if (items.length > 0) { + setSearchParams({ groupId: currentGroup }); + } else { + setSearchParams({}); + } + actionRef.current?.reload(); + }} + > + + + + ); + }} />
diff --git a/eiam-portal/src/main/portal-fe/src/pages/Application/data.d.ts b/eiam-portal/src/main/portal-fe/src/pages/Application/data.d.ts index ad21d5f4..2100eaeb 100644 --- a/eiam-portal/src/main/portal-fe/src/pages/Application/data.d.ts +++ b/eiam-portal/src/main/portal-fe/src/pages/Application/data.d.ts @@ -22,8 +22,8 @@ export type AppList = { template: string; icon?: string; name: string; - initLoginType: InitLoginType; - initLoginUrl: string; + initLoginType: InitLoginType | string; + initLoginUrl?: string; description: string; }; diff --git a/eiam-portal/src/main/portal-fe/src/pages/Application/locales/zh-CN.ts b/eiam-portal/src/main/portal-fe/src/pages/Application/locales/zh-CN.ts index 8a3f5ad1..94f0bf6e 100644 --- a/eiam-portal/src/main/portal-fe/src/pages/Application/locales/zh-CN.ts +++ b/eiam-portal/src/main/portal-fe/src/pages/Application/locales/zh-CN.ts @@ -16,8 +16,8 @@ * along with this program. If not, see . */ export default { - 'pages.application.search': '请输入', - 'pages.application.search.enter_button': '搜索', - 'pages.application.alert': '请点击下方的应用进行单点登录。若希望修改应用内容,请联系管理员。', + 'pages.application.search.name': '应用名称', + 'pages.application.tab.list': '应用列表', + 'pages.application.tab.account': '应用账号', 'pages.application.init.warning': '仅允许应用发起', }; diff --git a/eiam-portal/src/main/portal-fe/src/pages/Application/style.ts b/eiam-portal/src/main/portal-fe/src/pages/Application/style.ts index cfc8131c..917f46fb 100644 --- a/eiam-portal/src/main/portal-fe/src/pages/Application/style.ts +++ b/eiam-portal/src/main/portal-fe/src/pages/Application/style.ts @@ -24,7 +24,6 @@ const useStyles = createStyles(({ token, css, prefixCls }, prop) => { border: none; border-radius: ${token.borderRadius}; .${prefixCls}-pro-table-list-toolbar-container { - margin-bottom: 10px; } &-item-card {