diff --git a/src/views/Concept/components/HierarchyView.js b/src/views/Concept/components/HierarchyView.js
index bee38174..7da86f6e 100644
--- a/src/views/Concept/components/HierarchyView.js
+++ b/src/views/Concept/components/HierarchyView.js
@@ -30,8 +30,7 @@ import {
Layers,
Maximize2,
Minimize2,
- RefreshCw,
- Home,
+ ArrowLeft,
ChevronRight,
Brain,
Cpu,
@@ -350,15 +349,6 @@ const GlassCard = ({ item, onClick, size = 'normal' }) => {
)}
-
- {/* 外链图标 */}
- {isLeafConcept && (
-
- )}
{/* 底部:涨跌幅 */}
@@ -392,23 +382,44 @@ const GlassCard = ({ item, onClick, size = 'normal' }) => {
- {/* 展开标识 */}
+ {/* 展开标识 - 使用箭头图标 */}
{canDrillDown && (
+
+
+
+ )}
+
+ {/* 详情按钮 - 仅在 concept 层显示 */}
+ {isLeafConcept && (
- 展开
+ 详情 >
)}
@@ -422,6 +433,11 @@ const HierarchyView = ({
apiBaseUrl,
onSelectCategory,
selectedDate,
+ // 外部控制的 drillPath(可选,用于状态共享)
+ externalDrillPath,
+ onDrillPathChange,
+ // 是否隐藏导航和背景(由外部 ChartContainer 提供时设为 true)
+ hideNavigation = false,
}) => {
const [hierarchy, setHierarchy] = useState([]);
const [loading, setLoading] = useState(true);
@@ -431,12 +447,40 @@ const HierarchyView = ({
const [tradeDate, setTradeDate] = useState(null);
const [isFullscreen, setIsFullscreen] = useState(false);
- // 钻取状态
- const [currentLevel, setCurrentLevel] = useState('lv1');
- const [currentLv1, setCurrentLv1] = useState(null);
- const [currentLv2, setCurrentLv2] = useState(null);
- const [currentLv3, setCurrentLv3] = useState(null);
- const [breadcrumbs, setBreadcrumbs] = useState([{ label: '全部分类', level: 'root' }]);
+ // 内部钻取状态
+ const [internalDrillPath, setInternalDrillPath] = useState(null);
+
+ // 支持受控和非受控模式
+ const drillPath = externalDrillPath !== undefined ? externalDrillPath : internalDrillPath;
+ const setDrillPath = onDrillPathChange || setInternalDrillPath;
+
+ // 从 drillPath 派生当前层级和选中项
+ const currentLevel = useMemo(() => {
+ if (!drillPath) return 'lv1';
+ if (drillPath.lv3) return 'concept';
+ if (drillPath.lv2) return 'lv3';
+ if (drillPath.lv1) return 'lv2';
+ return 'lv1';
+ }, [drillPath]);
+
+ const currentLv1 = useMemo(() => drillPath?.lv1 ? { name: drillPath.lv1 } : null, [drillPath]);
+ const currentLv2 = useMemo(() => drillPath?.lv2 ? { name: drillPath.lv2 } : null, [drillPath]);
+ const currentLv3 = useMemo(() => drillPath?.lv3 ? { name: drillPath.lv3 } : null, [drillPath]);
+
+ // 面包屑从 drillPath 派生
+ const breadcrumbs = useMemo(() => {
+ const items = [{ label: '全部分类', level: 'root' }];
+ if (drillPath?.lv1) {
+ items.push({ label: drillPath.lv1, level: 'lv1', data: { name: drillPath.lv1 } });
+ }
+ if (drillPath?.lv2) {
+ items.push({ label: drillPath.lv2, level: 'lv2', data: { name: drillPath.lv2 } });
+ }
+ if (drillPath?.lv3) {
+ items.push({ label: drillPath.lv3, level: 'lv3', data: { name: drillPath.lv3 } });
+ }
+ return items;
+ }, [drillPath]);
const isMobile = useBreakpointValue({ base: true, md: false });
@@ -651,67 +695,43 @@ const HierarchyView = ({
logger.info('HierarchyView', '热力图点击', { level: item.level, name: item.name });
if (item.level === 'lv1' && item.children && item.children.length > 0) {
- setCurrentLevel('lv2');
- setCurrentLv1(item);
- setBreadcrumbs([
- { label: '全部分类', level: 'root' },
- { label: item.name, level: 'lv1', data: item },
- ]);
+ setDrillPath({ lv1: item.name });
} else if (item.level === 'lv2') {
- if (item.children && item.children.length > 0) {
- setCurrentLevel('lv3');
- setCurrentLv2(item);
- setBreadcrumbs([
- { label: '全部分类', level: 'root' },
- { label: currentLv1.name, level: 'lv1', data: currentLv1 },
- { label: item.name, level: 'lv2', data: item },
- ]);
- } else if (item.concepts && item.concepts.length > 0) {
- setCurrentLevel('lv3');
- setCurrentLv2(item);
- setBreadcrumbs([
- { label: '全部分类', level: 'root' },
- { label: currentLv1.name, level: 'lv1', data: currentLv1 },
- { label: item.name, level: 'lv2', data: item },
- ]);
+ if ((item.children && item.children.length > 0) || (item.concepts && item.concepts.length > 0)) {
+ setDrillPath({ lv1: drillPath?.lv1, lv2: item.name });
}
} else if (item.level === 'lv3' && item.concepts && item.concepts.length > 0) {
- setCurrentLevel('concept');
- setCurrentLv3(item);
- setBreadcrumbs([
- { label: '全部分类', level: 'root' },
- { label: currentLv1.name, level: 'lv1', data: currentLv1 },
- { label: currentLv2.name, level: 'lv2', data: currentLv2 },
- { label: item.name, level: 'lv3', data: item },
- ]);
+ setDrillPath({ lv1: drillPath?.lv1, lv2: drillPath?.lv2, lv3: item.name });
} else if (item.level === 'concept') {
// 跳转到概念详情页
const htmlPath = getConceptHtmlUrl(item.name);
window.open(htmlPath, '_blank');
}
- }, [currentLv1, currentLv2]);
+ }, [drillPath, setDrillPath]);
// 面包屑导航
const handleBreadcrumbClick = useCallback((crumb, index) => {
if (crumb.level === 'root') {
- setCurrentLevel('lv1');
- setCurrentLv1(null);
- setCurrentLv2(null);
- setCurrentLv3(null);
- setBreadcrumbs([{ label: '全部分类', level: 'root' }]);
+ setDrillPath(null);
} else if (crumb.level === 'lv1') {
- setCurrentLevel('lv2');
- setCurrentLv1(crumb.data);
- setCurrentLv2(null);
- setCurrentLv3(null);
- setBreadcrumbs(breadcrumbs.slice(0, index + 1));
+ setDrillPath({ lv1: crumb.data.name });
} else if (crumb.level === 'lv2') {
- setCurrentLevel('lv3');
- setCurrentLv2(crumb.data);
- setCurrentLv3(null);
- setBreadcrumbs(breadcrumbs.slice(0, index + 1));
+ setDrillPath({ lv1: drillPath?.lv1, lv2: crumb.data.name });
}
- }, [breadcrumbs]);
+ }, [drillPath, setDrillPath]);
+
+ // 返回上一层
+ const handleGoBack = useCallback(() => {
+ if (!drillPath) return;
+
+ if (drillPath.lv3) {
+ setDrillPath({ lv1: drillPath.lv1, lv2: drillPath.lv2 });
+ } else if (drillPath.lv2) {
+ setDrillPath({ lv1: drillPath.lv1 });
+ } else if (drillPath.lv1) {
+ setDrillPath(null);
+ }
+ }, [drillPath, setDrillPath]);
// 刷新
const handleRefreshPrice = useCallback(() => {
@@ -796,6 +816,22 @@ const HierarchyView = ({
);
}
+ // 当 hideNavigation 为 true 时,只渲染纯卡片网格内容
+ if (hideNavigation) {
+ return (
+
+ {currentData.map((item) => (
+
+ ))}
+
+ );
+ }
+
return (
{/* 面包屑导航 + 工具栏(同一行) */}
-
- {/* 左侧:面包屑导航 */}
-
- {breadcrumbs.map((crumb, index) => (
-
- {index > 0 && (
-
- )}
-
-
- ))}
-
-
- {/* 右侧:工具栏按钮 */}
-
- {priceLoading && (
-
+ onClick={handleGoBack}
+ 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"
+ />
+
)}
-
- }
- onClick={handleRefreshPrice}
- isLoading={priceLoading}
- bg="whiteAlpha.100"
- color="white"
- border="1px solid"
- borderColor="whiteAlpha.200"
- _hover={{ bg: 'whiteAlpha.200' }}
- aria-label="刷新涨跌幅"
- />
-
+
+ {breadcrumbs.map((crumb, index) => (
+
+ {index > 0 && (
+
+ )}
+ {
+ if (index < breadcrumbs.length - 1) {
+ handleBreadcrumbClick(crumb, index);
+ }
+ }}
+ transition="color 0.2s"
+ >
+ {crumb.label}
+
+
+ ))}
+
+
-
- : }
- onClick={toggleFullscreen}
- bg="whiteAlpha.100"
- color="white"
- border="1px solid"
- borderColor="whiteAlpha.200"
- _hover={{ bg: 'whiteAlpha.200' }}
- aria-label={isFullscreen ? '退出全屏' : '全屏'}
- />
-
-
-
-
- {/* 图例说明 */}
-
-
-
- 涨
-
-
-
- 跌
-
-
-
- 平/无数据
-
- |
-
- {currentLevel !== 'concept' ? '点击色块查看下级' : '点击查看概念详情'}
-
-
+ {/* 右侧:全屏按钮 */}
+
+ : }
+ 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"
+ aria-label={isFullscreen ? '退出全屏' : '全屏'}
+ />
+
+
{/* 热力图网格 */}
@@ -929,6 +952,47 @@ const HierarchyView = ({
))}
+ {/* 底部图例 */}
+
+
+
+
+ 涨
+
+
+
+
+ 跌
+
+
+
+
);