refactor: Community 目录结构重组 + 修复导入路径 + 添加 Mock 数据
## 目录重构 - DynamicNewsCard/ → DynamicNews/(含 layouts/, hooks/ 子目录) - EventCard 原子组件 → EventCard/atoms/ - EventDetailModal 独立目录化 - HotEvents 独立目录化(含 CSS) - SearchFilters 独立目录化(CompactSearchBox, TradingTimeFilter) ## 导入路径修复 - EventCard/*.js: 统一使用 @constants/, @utils/, @components/ 别名 - atoms/*.js: 修复移动后的相对路径问题 - DynamicNewsCard.js: 更新 contexts, store, constants 导入 - EventHeaderInfo.js, CompactMetaBar.js: 修复 EventFollowButton 导入 ## Mock Handler 添加 - /api/events/:eventId/expectation-score - 事件超预期得分 - /api/index/:indexCode/realtime - 指数实时行情 ## 警告修复 - CitationMark.js: overlayInnerStyle → styles (Antd 5.x) - CitedContent.js: 移除不支持的 jsx 属性 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
// src/views/Community/components/EventCard/atoms/EventPriceDisplay.js
|
||||
import React, { useState } from 'react';
|
||||
import { HStack, Box, Text, Tooltip, Progress } from '@chakra-ui/react';
|
||||
import { PriceArrow } from '@utils/priceFormatters';
|
||||
|
||||
/**
|
||||
* 事件价格变动显示组件
|
||||
* @param {Object} props
|
||||
* @param {number|null} props.avgChange - 平均涨跌幅
|
||||
* @param {number|null} props.maxChange - 最大涨跌幅
|
||||
* @param {number|null} props.expectationScore - 超预期得分(满分100)
|
||||
* @param {boolean} props.compact - 是否为紧凑模式(只显示平均值,默认 false)
|
||||
* @param {boolean} props.inline - 是否内联显示(默认 false)
|
||||
*/
|
||||
const EventPriceDisplay = ({
|
||||
avgChange,
|
||||
maxChange,
|
||||
expectationScore,
|
||||
compact = false,
|
||||
inline = false
|
||||
}) => {
|
||||
// 点击切换显示最大超额/平均超额
|
||||
const [showAvg, setShowAvg] = useState(false);
|
||||
|
||||
// 获取颜色方案
|
||||
const getColorScheme = (value) => {
|
||||
if (value == null) return 'gray';
|
||||
return value > 0 ? 'red' : value < 0 ? 'green' : 'gray';
|
||||
};
|
||||
|
||||
// 格式化百分比
|
||||
const formatPercent = (value) => {
|
||||
if (value == null) return '--';
|
||||
return `${value > 0 ? '+' : ''}${value.toFixed(2)}%`;
|
||||
};
|
||||
|
||||
// 获取超预期得分的颜色(渐变色系)
|
||||
const getScoreColor = (score) => {
|
||||
if (score == null) return { bg: 'gray.100', color: 'gray.500', progressColor: 'gray' };
|
||||
if (score >= 80) return { bg: 'red.50', color: 'red.600', progressColor: 'red' };
|
||||
if (score >= 60) return { bg: 'orange.50', color: 'orange.600', progressColor: 'orange' };
|
||||
if (score >= 40) return { bg: 'yellow.50', color: 'yellow.700', progressColor: 'yellow' };
|
||||
if (score >= 20) return { bg: 'blue.50', color: 'blue.600', progressColor: 'blue' };
|
||||
return { bg: 'gray.50', color: 'gray.600', progressColor: 'gray' };
|
||||
};
|
||||
|
||||
// 紧凑模式:只显示平均值,内联在标题后
|
||||
if (compact && avgChange != null) {
|
||||
return (
|
||||
<Tooltip label="平均超额" placement="top">
|
||||
<Box
|
||||
bg={avgChange > 0 ? 'red.50' : avgChange < 0 ? 'green.50' : 'gray.100'}
|
||||
color={avgChange > 0 ? 'red.600' : avgChange < 0 ? 'green.600' : 'gray.500'}
|
||||
fontSize="xs"
|
||||
px={2}
|
||||
py={1}
|
||||
borderRadius="md"
|
||||
fontWeight="bold"
|
||||
display={inline ? "inline-flex" : "flex"}
|
||||
alignItems="center"
|
||||
gap={1}
|
||||
verticalAlign="middle"
|
||||
>
|
||||
<PriceArrow value={avgChange} />
|
||||
{formatPercent(avgChange)}
|
||||
</Box>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
const displayValue = showAvg ? avgChange : maxChange;
|
||||
const displayLabel = showAvg ? '平均超额' : '最大超额';
|
||||
const scoreColors = getScoreColor(expectationScore);
|
||||
|
||||
// 详细模式:显示最大超额(可点击切换)+ 超预期得分
|
||||
return (
|
||||
<HStack spacing={3} flexWrap="wrap">
|
||||
{/* 最大超额/平均超额 - 点击切换 */}
|
||||
<Tooltip
|
||||
label={showAvg ? "点击查看最大超额" : "点击查看平均超额"}
|
||||
placement="top"
|
||||
hasArrow
|
||||
>
|
||||
<Box
|
||||
bg={displayValue > 0 ? 'red.50' : displayValue < 0 ? 'green.50' : 'gray.100'}
|
||||
color={displayValue > 0 ? 'red.600' : displayValue < 0 ? 'green.600' : 'gray.500'}
|
||||
fontSize="xs"
|
||||
px={2.5}
|
||||
py={1}
|
||||
borderRadius="md"
|
||||
cursor="pointer"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setShowAvg(!showAvg);
|
||||
}}
|
||||
_hover={{
|
||||
transform: 'scale(1.02)',
|
||||
boxShadow: 'sm',
|
||||
opacity: 0.9
|
||||
}}
|
||||
transition="all 0.2s"
|
||||
border="1px solid"
|
||||
borderColor={displayValue > 0 ? 'red.200' : displayValue < 0 ? 'green.200' : 'gray.200'}
|
||||
>
|
||||
<HStack spacing={1.5}>
|
||||
<Text fontSize="xs" opacity={0.7} fontWeight="medium">{displayLabel}</Text>
|
||||
<Text fontWeight="bold" fontSize="sm">
|
||||
{formatPercent(displayValue)}
|
||||
</Text>
|
||||
</HStack>
|
||||
</Box>
|
||||
</Tooltip>
|
||||
|
||||
{/* 超预期得分 - 精致的进度条样式 */}
|
||||
{expectationScore != null && (
|
||||
<Tooltip
|
||||
label={`超预期得分:${expectationScore.toFixed(0)}分(满分100分)`}
|
||||
placement="top"
|
||||
hasArrow
|
||||
>
|
||||
<Box
|
||||
bg={scoreColors.bg}
|
||||
px={2.5}
|
||||
py={1}
|
||||
borderRadius="md"
|
||||
border="1px solid"
|
||||
borderColor={`${scoreColors.progressColor}.200`}
|
||||
minW="90px"
|
||||
>
|
||||
<HStack spacing={2}>
|
||||
<Text fontSize="xs" color={scoreColors.color} fontWeight="medium" opacity={0.8}>
|
||||
超预期
|
||||
</Text>
|
||||
<Box flex={1} minW="40px">
|
||||
<Progress
|
||||
value={expectationScore}
|
||||
max={100}
|
||||
size="xs"
|
||||
colorScheme={scoreColors.progressColor}
|
||||
borderRadius="full"
|
||||
bg={`${scoreColors.progressColor}.100`}
|
||||
/>
|
||||
</Box>
|
||||
<Text fontSize="xs" fontWeight="bold" color={scoreColors.color}>
|
||||
{expectationScore.toFixed(0)}
|
||||
</Text>
|
||||
</HStack>
|
||||
</Box>
|
||||
</Tooltip>
|
||||
)}
|
||||
</HStack>
|
||||
);
|
||||
};
|
||||
|
||||
export default EventPriceDisplay;
|
||||
Reference in New Issue
Block a user