From 70dbf3b4923a40f62b57af5c9d02078c409783b8 Mon Sep 17 00:00:00 2001
From: zdl <3489966805@qq.com>
Date: Wed, 5 Nov 2025 15:19:48 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20StockChangeIndicators=20=E7=BB=84?=
=?UTF-8?q?=E4=BB=B6=E4=BC=98=E5=8C=96?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/components/StockChangeIndicators.js | 146 +++++++++++-------------
1 file changed, 66 insertions(+), 80 deletions(-)
diff --git a/src/components/StockChangeIndicators.js b/src/components/StockChangeIndicators.js
index 58220228..922a4fc7 100644
--- a/src/components/StockChangeIndicators.js
+++ b/src/components/StockChangeIndicators.js
@@ -3,6 +3,7 @@
import React from 'react';
import { Flex, Box, Text, useColorModeValue } from '@chakra-ui/react';
+import { TriangleUpIcon, TriangleDownIcon } from '@chakra-ui/icons';
/**
* 股票涨跌幅指标组件(3分天下布局)
@@ -10,13 +11,18 @@ import { Flex, Box, Text, useColorModeValue } from '@chakra-ui/react';
* @param {number} props.avgChange - 平均涨跌幅
* @param {number} props.maxChange - 最大涨跌幅
* @param {number} props.weekChange - 周涨跌幅
+ * @param {'default'|'comfortable'|'large'} props.size - 尺寸模式:default=紧凑,comfortable=舒适(事件列表),large=大卡片(详情面板)
*/
const StockChangeIndicators = ({
avgChange,
maxChange,
weekChange,
+ size = 'default',
}) => {
- // 根据涨跌幅获取数字颜色(多颜色梯度:5级分级)
+ const isLarge = size === 'large';
+ const isComfortable = size === 'comfortable';
+
+ // 根据涨跌幅获取数字颜色(统一颜色,不分级)
const getNumberColor = (value) => {
if (value == null) {
return useColorModeValue('gray.700', 'gray.400');
@@ -27,24 +33,8 @@ const StockChangeIndicators = ({
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%:浅青
- }
+ // 统一颜色:上涨红色,下跌绿色
+ return value > 0 ? 'red.500' : 'green.500';
};
// 根据涨跌幅获取背景色(永远比文字色浅)
@@ -58,24 +48,10 @@ const StockChangeIndicators = ({
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');
- }
+ // 统一背景色:上涨红色系,下跌绿色系
+ return value > 0
+ ? useColorModeValue('red.50', 'red.900')
+ : useColorModeValue('green.50', 'green.900');
};
// 根据涨跌幅获取边框色(比背景深,比文字浅)
@@ -89,64 +65,74 @@ const StockChangeIndicators = ({
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
- }
+ // 统一边框色:上涨红色系,下跌绿色系
+ return value > 0
+ ? useColorModeValue('red.200', 'red.700')
+ : useColorModeValue('green.200', 'green.700');
};
// 渲染单个指标
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 sign = value > 0 ? '+' : '-';
+ // 0值显示为 "0",其他值显示两位小数
+ const numStr = value === 0 ? '0' : Math.abs(value).toFixed(2);
const numberColor = getNumberColor(value);
const bgColor = getBgColor(value);
const borderColor = getBorderColor(value);
- const labelColor = useColorModeValue('gray.700', 'gray.400');
+ const labelColor = useColorModeValue('gray.600', 'gray.400');
return (
-
-
- {label}
+ {/* Large 模式:标签单独一行 */}
+ {isLarge && (
+
+ {label.trim()}
-
- {sign}
+ )}
+
+ {/* 数值 + 图标 */}
+
+ {/* 三角形图标 */}
+ {value !== 0 && (
+ value > 0 ? (
+
+ ) : (
+
+ )
+ )}
+
+ {/* 数字 */}
+
+ {/* Default 模式:标签和数字在同一行 */}
+ {!isLarge && (
+
+ {label}
+
+ )}
+ {sign}{numStr}%
-
- {value < 0 ? '-' : ''}{numStr}
-
-
- %
-
-
+
);
};
@@ -157,10 +143,10 @@ const StockChangeIndicators = ({
}
return (
-
- {renderIndicator('平均 ', avgChange)}
- {renderIndicator('最大 ', maxChange)}
- {renderIndicator('周涨 ', weekChange)}
+
+ {renderIndicator('平均涨幅', avgChange)}
+ {renderIndicator('最大涨幅', maxChange)}
+ {renderIndicator('周涨幅', weekChange)}
);
};