From acf5fe08b54f4edcc0189eadefcde6532ff6e317 Mon Sep 17 00:00:00 2001 From: Zeke Zhang <958414905@qq.com> Date: Tue, 19 May 2026 08:20:44 +0800 Subject: [PATCH] fix(client): hide zero route badge (#9491) --- .../antd/admin-layout/__tests__/badge.test.ts | 32 +++++++++++++++++++ .../route-switch/antd/admin-layout/badge.ts | 18 +++++++++++ .../route-switch/antd/admin-layout/index.tsx | 20 ++++++++---- .../src/schema-component/antd/page/Page.tsx | 3 +- 4 files changed, 65 insertions(+), 8 deletions(-) create mode 100644 packages/core/client/src/route-switch/antd/admin-layout/__tests__/badge.test.ts create mode 100644 packages/core/client/src/route-switch/antd/admin-layout/badge.ts diff --git a/packages/core/client/src/route-switch/antd/admin-layout/__tests__/badge.test.ts b/packages/core/client/src/route-switch/antd/admin-layout/__tests__/badge.test.ts new file mode 100644 index 00000000000..b64ba2bf005 --- /dev/null +++ b/packages/core/client/src/route-switch/antd/admin-layout/__tests__/badge.test.ts @@ -0,0 +1,32 @@ +/** + * This file is part of the NocoBase (R) project. + * Copyright (c) 2020-2024 NocoBase Co., Ltd. + * Authors: NocoBase Team. + * + * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License. + * For more information, please refer to: https://www.nocobase.com/agreement. + */ + +import { shouldDisplayRouteBadge } from '../badge'; + +describe('shouldDisplayRouteBadge', () => { + it('should hide zero badge by default', () => { + expect(shouldDisplayRouteBadge(0)).toBe(false); + expect(shouldDisplayRouteBadge('0')).toBe(false); + }); + + it('should show zero badge when showZero is enabled', () => { + expect(shouldDisplayRouteBadge(0, true)).toBe(true); + expect(shouldDisplayRouteBadge('0', true)).toBe(true); + }); + + it('should show non-zero badge values', () => { + expect(shouldDisplayRouteBadge(1)).toBe(true); + expect(shouldDisplayRouteBadge('待处理')).toBe(true); + }); + + it('should hide empty badge values', () => { + expect(shouldDisplayRouteBadge(null)).toBe(false); + expect(shouldDisplayRouteBadge(undefined)).toBe(false); + }); +}); diff --git a/packages/core/client/src/route-switch/antd/admin-layout/badge.ts b/packages/core/client/src/route-switch/antd/admin-layout/badge.ts new file mode 100644 index 00000000000..53d1707e97e --- /dev/null +++ b/packages/core/client/src/route-switch/antd/admin-layout/badge.ts @@ -0,0 +1,18 @@ +/** + * This file is part of the NocoBase (R) project. + * Copyright (c) 2020-2024 NocoBase Co., Ltd. + * Authors: NocoBase Team. + * + * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License. + * For more information, please refer to: https://www.nocobase.com/agreement. + */ + +export type RouteBadgeCount = number | string | null | undefined; + +export const isZeroRouteBadgeCount = (count: RouteBadgeCount) => { + return count === 0 || count === '0'; +}; + +export const shouldDisplayRouteBadge = (count: RouteBadgeCount, showZero?: boolean) => { + return count != null && (!isZeroRouteBadgeCount(count) || !!showZero); +}; diff --git a/packages/core/client/src/route-switch/antd/admin-layout/index.tsx b/packages/core/client/src/route-switch/antd/admin-layout/index.tsx index 77d2af2d3d9..857527586bd 100644 --- a/packages/core/client/src/route-switch/antd/admin-layout/index.tsx +++ b/packages/core/client/src/route-switch/antd/admin-layout/index.tsx @@ -56,6 +56,7 @@ import { useEvaluatedExpression } from '../../../hooks/useParsedValue'; import { menuItemInitializer } from '../../../modules/menu/menuItemInitializer'; import { useMenuTranslation } from '../../../schema-component/antd/menu/locale'; import { VariableScope } from '../../../variables/VariableScope'; +import { shouldDisplayRouteBadge } from './badge'; import { KeepAlive, useKeepAlive } from './KeepAlive'; import { NocoBaseDesktopRoute, NocoBaseDesktopRouteType } from './convertRoutesToSchema'; import { MenuSchemaToolbar, ResetThemeTokenAndKeepAlgorithm } from './menuItemSettings'; @@ -339,7 +340,7 @@ const GroupItem: FC<{ item: any }> = (props) => { {props.children} {designable && } - {badgeCount != null && ( + {shouldDisplayRouteBadge(badgeCount, item._route.options?.badge?.showZero) && ( = (pr {(context) => context.collapsed && !props.hidden && !inHeader ? ( - - {props.children} - + {props.badgeProps ? ( + + {props.children} + + ) : ( + props.children + )} ) : ( props.children @@ -384,7 +389,8 @@ const MenuItem: FC<{ item: any; options: { isMobile: boolean; collapsed: boolean const { closeMobileMenu } = useContext(MobileMenuControlContext); // 如果点击的是一个 group,直接跳转到第一个子页面 const path = item.redirect || item.path; - const badgeProps = { ...item._route.options?.badge, count: badgeCount }; + const showBadge = shouldDisplayRouteBadge(badgeCount, item._route.options?.badge?.showZero); + const badgeProps = showBadge ? { ...item._route.options?.badge, count: badgeCount } : null; useEffect(() => { if (divRef.current) { @@ -487,7 +493,7 @@ const MenuItem: FC<{ item: any; options: { isMobile: boolean; collapsed: boolean - {badgeCount != null && ( + {showBadge && ( - {badgeCount != null && ( + {showBadge && ( { const TabBadge: FC<{ tabRoute: NocoBaseDesktopRoute; style?: React.CSSProperties }> = (props) => { const badgeCount = useEvaluatedExpression(props.tabRoute.options?.badge?.count); - if (badgeCount == null) return null; + if (!shouldDisplayRouteBadge(badgeCount, props.tabRoute.options?.badge?.showZero)) return null; return (