## 目录重构 - 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>
156 lines
6.3 KiB
JavaScript
156 lines
6.3 KiB
JavaScript
// 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;
|