From 5ae05eebd8aeb0ff79d292df0d5b9efe6798ee6a Mon Sep 17 00:00:00 2001 From: zdl <3489966805@qq.com> Date: Thu, 8 Jan 2026 19:03:49 +0800 Subject: [PATCH] =?UTF-8?q?feat(Concept):=20=E6=96=B0=E5=A2=9E=E7=BB=9F?= =?UTF-8?q?=E4=B8=80=E5=9B=BE=E8=A1=A8=E5=AE=B9=E5=99=A8=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ChartBreadcrumb.js: 通用面包屑导航组件 - ChartContainer.js: 统一图表容器 - 极光背景动画 - 面包屑导航(左上角) - 全屏按钮(右上角) - 底部图例(可选) - contentTopPadding 可配置内边距 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../Concept/components/ChartBreadcrumb.js | 96 +++++++ .../Concept/components/ChartContainer.js | 246 ++++++++++++++++++ 2 files changed, 342 insertions(+) create mode 100644 src/views/Concept/components/ChartBreadcrumb.js create mode 100644 src/views/Concept/components/ChartContainer.js diff --git a/src/views/Concept/components/ChartBreadcrumb.js b/src/views/Concept/components/ChartBreadcrumb.js new file mode 100644 index 00000000..110f96ad --- /dev/null +++ b/src/views/Concept/components/ChartBreadcrumb.js @@ -0,0 +1,96 @@ +/** + * ChartBreadcrumb - 图表通用面包屑导航组件 + * + * 用于矩形树图和层级图共享的面包屑导航 + */ +import React, { memo } from 'react'; +import { + HStack, + Text, + Icon, + Tooltip, + IconButton, +} from '@chakra-ui/react'; +import { ArrowLeft, ChevronRight } from 'lucide-react'; +import { GLASS_BLUR } from '@/constants/glassConfig'; + +/** + * Props: + * @param {Array<{label: string, path: object|null}>} items - 面包屑项目 + * @param {function} onNavigate - 导航回调 (path) => void + * @param {function} onGoBack - 返回上一层回调 + * @param {boolean} showBackButton - 是否显示返回按钮 + */ +const ChartBreadcrumb = memo(({ + items = [], + onNavigate, + onGoBack, + showBackButton = false, +}) => { + return ( + + {/* 返回按钮 */} + {showBackButton && ( + + } + size="sm" + variant="ghost" + onClick={onGoBack} + bg="rgba(255, 255, 255, 0.08)" + backdropFilter={GLASS_BLUR.lg} + border="1px solid" + borderColor="whiteAlpha.100" + color="whiteAlpha.800" + borderRadius="full" + _hover={{ + bg: 'rgba(255, 255, 255, 0.15)', + transform: 'scale(1.05)', + }} + transition="all 0.2s" + /> + + )} + + {/* 面包屑路径 */} + + {items.map((item, index) => ( + + {index > 0 && ( + + )} + { + if (index < items.length - 1 && onNavigate) { + onNavigate(item.path); + } + }} + transition="color 0.2s" + > + {item.label} + + + ))} + + + ); +}); + +ChartBreadcrumb.displayName = 'ChartBreadcrumb'; + +export default ChartBreadcrumb; diff --git a/src/views/Concept/components/ChartContainer.js b/src/views/Concept/components/ChartContainer.js new file mode 100644 index 00000000..457e2938 --- /dev/null +++ b/src/views/Concept/components/ChartContainer.js @@ -0,0 +1,246 @@ +/** + * ChartContainer - 图表统一容器组件 + * + * 用于矩形树图和层级图的统一容器,包含: + * - 极光背景动画 + * - 面包屑导航 + * - 全屏按钮 + * - 底部图例(可选) + */ +import React, { memo, useCallback, useState } from 'react'; +import { + Box, + HStack, + Text, + Tooltip, + IconButton, + useBreakpointValue, +} from '@chakra-ui/react'; +import { keyframes } from '@emotion/react'; +import { Maximize2, Minimize2 } from 'lucide-react'; +import { GLASS_BLUR } from '@/constants/glassConfig'; +import ChartBreadcrumb from './ChartBreadcrumb'; + +// 极光动画 +const auroraAnimation = keyframes` + 0%, 100% { + background-position: 0% 50%; + filter: hue-rotate(0deg); + } + 25% { + background-position: 50% 100%; + filter: hue-rotate(10deg); + } + 50% { + background-position: 100% 50%; + filter: hue-rotate(0deg); + } + 75% { + background-position: 50% 0%; + filter: hue-rotate(-10deg); + } +`; + +// 光晕脉冲动画 +const glowPulse = keyframes` + 0%, 100% { opacity: 0.3; transform: scale(1); } + 50% { opacity: 0.6; transform: scale(1.05); } +`; + +/** + * Props: + * @param {Array} breadcrumbItems - 面包屑项目 + * @param {function} onNavigate - 导航回调 + * @param {function} onGoBack - 返回回调 + * @param {boolean} showBackButton - 是否显示返回按钮 + * @param {boolean} showLegend - 是否显示底部图例 + * @param {string} height - 容器高度 + * @param {number} contentTopPadding - 内容区顶部内边距(避开导航栏) + * @param {ReactNode} children - 图表内容 + */ +const ChartContainer = memo(({ + breadcrumbItems = [], + onNavigate, + onGoBack, + showBackButton = false, + showLegend = false, + height, + contentTopPadding = 14, + children, +}) => { + const [isFullscreen, setIsFullscreen] = useState(false); + const isMobile = useBreakpointValue({ base: true, md: false }); + + const toggleFullscreen = useCallback(() => { + setIsFullscreen(prev => !prev); + }, []); + + // 计算容器高度 + const containerHeight = isFullscreen + ? 'calc(100vh - 60px)' + : height || (isMobile ? '500px' : '700px'); + + return ( + + {/* 极光背景层 */} + + + {/* 弥散光晕层 */} + + + + + {/* 左上角面包屑导航 */} + + + + + {/* 右上角全屏按钮 */} + + : } + size="sm" + variant="ghost" + onClick={toggleFullscreen} + bg="rgba(255, 255, 255, 0.08)" + backdropFilter={GLASS_BLUR.lg} + border="1px solid" + borderColor="whiteAlpha.100" + color="whiteAlpha.800" + borderRadius="full" + _hover={{ + bg: 'rgba(255, 255, 255, 0.15)', + transform: 'scale(1.05)', + }} + transition="all 0.2s" + /> + + + {/* 底部图例 */} + {showLegend && ( + + + + + + + + + + + + )} + + {/* 图表内容 - 添加顶部和底部内边距避开导航和图例 */} + + {children} + + + ); +}); + +ChartContainer.displayName = 'ChartContainer'; + +export default ChartContainer;