feat: RelatedConceptsSection 支持受控模式和优化

- 新增 isOpen, onToggle props 支持外部控制展开状态(受控模式)
- 添加 hasNoConcepts 判断,优化空数据处理逻辑
- 改进精简模式和详细模式的空状态显示
- 增强点击处理逻辑,支持受控/非受控两种模式

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
zdl
2025-11-07 19:46:29 +08:00
parent b30cbd6c62
commit 4979293320
2 changed files with 54 additions and 27 deletions

View File

@@ -10,6 +10,8 @@ import {
Text, Text,
Spinner, Spinner,
Center, Center,
Wrap,
WrapItem,
useColorModeValue, useColorModeValue,
useToast, useToast,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
@@ -32,8 +34,9 @@ import SubscriptionUpgradeModal from '../../../../components/SubscriptionUpgrade
* 动态新闻详情面板主组件 * 动态新闻详情面板主组件
* @param {Object} props * @param {Object} props
* @param {Object} props.event - 事件对象(包含详情数据) * @param {Object} props.event - 事件对象(包含详情数据)
* @param {boolean} props.showHeader - 是否显示头部信息(默认 true
*/ */
const DynamicNewsDetailPanel = ({ event }) => { const DynamicNewsDetailPanel = ({ event, showHeader = true }) => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const { user } = useAuth(); const { user } = useAuth();
const cardBg = useColorModeValue('white', 'gray.800'); const cardBg = useColorModeValue('white', 'gray.800');

View File

@@ -38,9 +38,13 @@ const RelatedConceptsSection = ({
eventTime, eventTime,
subscriptionBadge = null, subscriptionBadge = null,
isLocked = false, isLocked = false,
onLockedClick = null onLockedClick = null,
isOpen = undefined, // 新增:受控模式(外部控制展开状态)
onToggle = undefined // 新增:受控模式(外部控制展开回调)
}) => { }) => {
const [isExpanded, setIsExpanded] = useState(false); // 使用外部 isOpen如果没有则使用内部 useState
const [internalExpanded, setInternalExpanded] = useState(false);
const isExpanded = onToggle !== undefined ? isOpen : internalExpanded;
const [concepts, setConcepts] = useState([]); const [concepts, setConcepts] = useState([]);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [error, setError] = useState(null); const [error, setError] = useState(null);
@@ -179,10 +183,8 @@ const RelatedConceptsSection = ({
); );
} }
// 如果没有概念,不渲染 // 判断是否有数据
if (!concepts || concepts.length === 0) { const hasNoConcepts = !concepts || concepts.length === 0;
return null;
}
/** /**
* 根据相关度获取颜色(浅色背景 + 深色文字) * 根据相关度获取颜色(浅色背景 + 深色文字)
@@ -232,9 +234,12 @@ const RelatedConceptsSection = ({
// 如果被锁定且有回调函数,触发付费弹窗 // 如果被锁定且有回调函数,触发付费弹窗
if (isLocked && onLockedClick) { if (isLocked && onLockedClick) {
onLockedClick(); onLockedClick();
} else if (onToggle !== undefined) {
// 受控模式:调用外部回调
onToggle();
} else { } else {
// 否则正常展开/收起 // 非受控模式:使用内部状态
setIsExpanded(!isExpanded); setInternalExpanded(!internalExpanded);
} }
}} }}
> >
@@ -249,30 +254,49 @@ const RelatedConceptsSection = ({
</Box> </Box>
{/* 简单模式:横向卡片列表(总是显示) */} {/* 简单模式:横向卡片列表(总是显示) */}
<Flex gap={2} flexWrap="wrap" mb={isExpanded ? 3 : 0}> {hasNoConcepts ? (
{concepts.map((concept, index) => ( <Box mb={isExpanded ? 3 : 0}>
<SimpleConceptCard {error ? (
key={index} <Text color="red.500" fontSize="sm">{error}</Text>
concept={concept} ) : (
onClick={handleConceptClick} <Text color={textColor} fontSize="sm">暂无相关概念数据</Text>
getRelevanceColor={getRelevanceColor} )}
/> </Box>
))} ) : (
</Flex> <Flex gap={2} flexWrap="wrap" mb={isExpanded ? 3 : 0}>
{/* 详细模式:卡片网格(可折叠) */}
<Collapse in={isExpanded} animateOpacity>
{/* 详细概念卡片网格 */}
<SimpleGrid columns={{ base: 1, md: 2 }} spacing={4}>
{concepts.map((concept, index) => ( {concepts.map((concept, index) => (
<DetailedConceptCard <SimpleConceptCard
key={index} key={index}
concept={concept} concept={concept}
onClick={handleConceptClick} onClick={handleConceptClick}
getRelevanceColor={getRelevanceColor}
/> />
))} ))}
</SimpleGrid> </Flex>
)}
{/* 详细模式:卡片网格(可折叠) */}
<Collapse in={isExpanded} animateOpacity>
{hasNoConcepts ? (
<Box py={4}>
{error ? (
<Text color="red.500" fontSize="sm" textAlign="center">{error}</Text>
) : (
<Text color={textColor} fontSize="sm" textAlign="center">暂无详细数据</Text>
)}
</Box>
) : (
/* 详细概念卡片网格 */
<SimpleGrid columns={{ base: 1, md: 2 }} spacing={4}>
{concepts.map((concept, index) => (
<DetailedConceptCard
key={index}
concept={concept}
onClick={handleConceptClick}
/>
))}
</SimpleGrid>
)}
</Collapse> </Collapse>
</Box> </Box>
); );