// src/components/StockChangeIndicators.js // 股票涨跌幅指标组件(通用) import React from 'react'; import { Flex, Box, Text, useColorModeValue } from '@chakra-ui/react'; /** * 股票涨跌幅指标组件(3分天下布局) * @param {Object} props * @param {number} props.avgChange - 平均涨跌幅 * @param {number} props.maxChange - 最大涨跌幅 * @param {number} props.weekChange - 周涨跌幅 */ const StockChangeIndicators = ({ avgChange, maxChange, weekChange, }) => { // 根据涨跌幅获取数字颜色(多颜色梯度:5级分级) const getNumberColor = (value) => { if (value == null) { return useColorModeValue('gray.700', 'gray.400'); } // 0值使用中性灰色 if (value === 0) { return 'gray.700'; } const absValue = Math.abs(value); const isPositive = value > 0; if (isPositive) { // 上涨:红色系 → 橙色系 if (absValue >= 10) return 'red.900'; // 10%以上:最深红 if (absValue >= 5) return 'red.700'; // 5-10%:深红 if (absValue >= 3) return 'red.500'; // 3-5%:中红 if (absValue >= 1) return 'orange.600'; // 1-3%:橙色 return 'orange.400'; // 0-1%:浅橙 } else { // 下跌:绿色系 → 青色系 if (absValue >= 10) return 'green.900'; // -10%以下:最深绿 if (absValue >= 5) return 'green.700'; // -10% ~ -5%:深绿 if (absValue >= 3) return 'green.500'; // -5% ~ -3%:中绿 if (absValue >= 1) return 'teal.600'; // -3% ~ -1%:青色 return 'teal.400'; // -1% ~ 0%:浅青 } }; // 根据涨跌幅获取背景色(永远比文字色浅) const getBgColor = (value) => { if (value == null) { return useColorModeValue('gray.50', 'gray.800'); } // 0值使用中性灰色背景 if (value === 0) { return useColorModeValue('gray.50', 'gray.800'); } const absValue = Math.abs(value); const isPositive = value > 0; if (isPositive) { // 上涨背景:红色系 → 橙色系(统一使用 50 最浅色) if (absValue >= 10) return useColorModeValue('red.50', 'red.900'); if (absValue >= 5) return useColorModeValue('red.50', 'red.900'); if (absValue >= 3) return useColorModeValue('red.50', 'red.900'); if (absValue >= 1) return useColorModeValue('orange.50', 'orange.900'); return useColorModeValue('orange.50', 'orange.900'); } else { // 下跌背景:绿色系 → 青色系(统一使用 50 最浅色) if (absValue >= 10) return useColorModeValue('green.50', 'green.900'); if (absValue >= 5) return useColorModeValue('green.50', 'green.900'); if (absValue >= 3) return useColorModeValue('green.50', 'green.900'); if (absValue >= 1) return useColorModeValue('teal.50', 'teal.900'); return useColorModeValue('teal.50', 'teal.900'); } }; // 根据涨跌幅获取边框色(比背景深,比文字浅) const getBorderColor = (value) => { if (value == null) { return useColorModeValue('gray.200', 'gray.700'); } // 0值使用中性灰色边框 if (value === 0) { return useColorModeValue('gray.200', 'gray.700'); } const absValue = Math.abs(value); const isPositive = value > 0; if (isPositive) { // 上涨边框:红色系 → 橙色系(跟随文字深浅) if (absValue >= 10) return useColorModeValue('red.200', 'red.800'); // 文字 red.900 if (absValue >= 5) return useColorModeValue('red.200', 'red.700'); // 文字 red.700 if (absValue >= 3) return useColorModeValue('red.100', 'red.600'); // 文字 red.500 if (absValue >= 1) return useColorModeValue('orange.200', 'orange.700'); // 文字 orange.600 return useColorModeValue('orange.100', 'orange.600'); // 文字 orange.400 } else { // 下跌边框:绿色系 → 青色系(跟随文字深浅) if (absValue >= 10) return useColorModeValue('green.200', 'green.800'); // 文字 green.900 if (absValue >= 5) return useColorModeValue('green.200', 'green.700'); // 文字 green.700 if (absValue >= 3) return useColorModeValue('green.100', 'green.600'); // 文字 green.500 if (absValue >= 1) return useColorModeValue('teal.200', 'teal.700'); // 文字 teal.600 return useColorModeValue('teal.100', 'teal.600'); // 文字 teal.400 } }; // 渲染单个指标 const renderIndicator = (label, value) => { if (value == null) return null; const sign = value > 0 ? '+' : ''; // 0值显示为 "0",其他值显示一位小数 const numStr = value === 0 ? '0' : Math.abs(value).toFixed(1); const numberColor = getNumberColor(value); const bgColor = getBgColor(value); const borderColor = getBorderColor(value); const labelColor = useColorModeValue('gray.700', 'gray.400'); return ( {label} {sign} {value < 0 ? '-' : ''}{numStr} % ); }; // 如果没有任何数据,不渲染 if (avgChange == null && maxChange == null && weekChange == null) { return null; } return ( {renderIndicator('平均 ', avgChange)} {renderIndicator('最大 ', maxChange)} {renderIndicator('周涨 ', weekChange)} ); }; export default StockChangeIndicators;