update pay promo

This commit is contained in:
2026-02-03 14:19:17 +08:00
parent 390f6024f4
commit 61bbcef58c
4 changed files with 301 additions and 2 deletions

View File

@@ -10,7 +10,7 @@ import type { KLineModuleProps, OverlayMetricData } from '../../../types';
import type { ChartMode } from './constants';
// 子组件导入
import { KLineToolbar, DailyKLineChart, MinuteChartWithOrderBook } from './components';
import { KLineToolbar, DailyKLineChart, MinuteChartWithOrderBook, IndicatorGuide } from './components';
// 重新导出类型供外部使用
export type { KLineModuleProps } from '../../../types';
@@ -40,6 +40,7 @@ const KLineModule: React.FC<KLineModuleProps> = ({
const [drawingType, setDrawingType] = useState<DrawingType>('NONE');
const [overlayMetrics, setOverlayMetrics] = useState<OverlayMetricData[]>([]);
const [showOrderBook, setShowOrderBook] = useState<boolean>(true);
const [showIndicatorGuide, setShowIndicatorGuide] = useState<boolean>(false);
// ========== 计算属性 ==========
const hasMinuteData = minuteData && minuteData.data && minuteData.data.length > 0;
@@ -73,6 +74,11 @@ const KLineModule: React.FC<KLineModuleProps> = ({
setShowOrderBook(prev => !prev);
}, []);
// 切换显示/隐藏指标说明
const handleToggleIndicatorGuide = useCallback(() => {
setShowIndicatorGuide(prev => !prev);
}, []);
// 添加叠加指标
const handleAddOverlayMetric = useCallback((metric: OverlayMetricData) => {
setOverlayMetrics(prev => [...prev, metric]);
@@ -119,6 +125,8 @@ const KLineModule: React.FC<KLineModuleProps> = ({
onAddOverlayMetric={handleAddOverlayMetric}
onRemoveOverlayMetric={handleRemoveOverlayMetric}
stockDateRange={stockDateRange}
showIndicatorGuide={showIndicatorGuide}
onToggleIndicatorGuide={handleToggleIndicatorGuide}
minuteData={minuteData}
minuteLoading={minuteLoading}
showOrderBook={showOrderBook}
@@ -126,6 +134,9 @@ const KLineModule: React.FC<KLineModuleProps> = ({
onRefreshMinuteData={onLoadMinuteData}
/>
{/* 指标说明面板(可折叠) */}
{mode === 'daily' && <IndicatorGuide isOpen={showIndicatorGuide} />}
{/* 图表内容区域 */}
<Box pt={4}>
{/* 加载中骨架屏 */}

View File

@@ -0,0 +1,266 @@
// src/views/Company/components/MarketDataView/components/panels/TradeDataPanel/components/IndicatorGuide.tsx
// 技术指标说明组件 - 可折叠面板
import React, { memo } from 'react';
import {
Box,
Text,
VStack,
HStack,
Collapse,
Badge,
SimpleGrid,
Divider,
} from '@chakra-ui/react';
import { darkGoldTheme } from '../../../../constants';
interface IndicatorGuideProps {
isOpen: boolean;
}
// 自定义颜色(补充主题中没有的颜色)
const INDICATOR_COLORS = {
cyan: '#00BCD4',
magenta: '#E040FB',
gold: darkGoldTheme.gold,
green: darkGoldTheme.green,
orange: darkGoldTheme.orange,
};
// 指标说明数据
const INDICATOR_DEFINITIONS = {
main: [
{
name: 'MA移动平均线',
abbr: 'MA',
formula: 'MA(N) = 最近N日收盘价之和 / N',
description: '反映一段时间内的平均成本,用于判断趋势方向。',
params: 'MA5、MA10、MA20',
usage: '短期MA上穿长期MA为金叉买入信号下穿为死叉卖出信号',
color: INDICATOR_COLORS.cyan,
},
{
name: 'BOLL布林带',
abbr: 'BOLL',
formula: '中轨 = MA(20)\n上轨 = 中轨 + 2×标准差\n下轨 = 中轨 - 2×标准差',
description: '基于统计学原理,显示价格的波动范围和趋势。',
params: '周期20标准差倍数2',
usage: '价格触及上轨可能超买,触及下轨可能超卖;收窄预示变盘',
color: INDICATOR_COLORS.magenta,
},
],
sub: [
{
name: 'MACD平滑异同移动平均线',
abbr: 'MACD',
formula: 'DIF = EMA(12) - EMA(26)\nDEA = EMA(DIF, 9)\nMACD柱 = (DIF - DEA) × 2',
description: '趋势跟踪指标,用于判断买卖时机和趋势强弱。',
params: '快线12慢线26信号线9',
usage: 'DIF上穿DEA为金叉买入下穿为死叉卖出柱状体由负转正看多',
color: INDICATOR_COLORS.gold,
},
{
name: 'KDJ随机指标',
abbr: 'KDJ',
formula: 'RSV = (收盘价-最低价)/(最高价-最低价)×100\nK = 2/3×前K + 1/3×RSV\nD = 2/3×前D + 1/3×K\nJ = 3K - 2D',
description: '动量指标,反映价格相对于近期波动范围的位置。',
params: '周期9K平滑3D平滑3',
usage: 'K/D<20超卖区>80超买区K上穿D为金叉J值>100超买<0超卖',
color: INDICATOR_COLORS.cyan,
},
{
name: 'RSI相对强弱指标',
abbr: 'RSI',
formula: 'RS = 平均涨幅 / 平均跌幅\nRSI = 100 - 100/(1+RS)',
description: '衡量价格变动的速度和幅度,判断超买超卖。',
params: 'RSI6短期、RSI12中期、RSI24长期',
usage: 'RSI>70超买区<30超卖区背离现象预示反转',
color: INDICATOR_COLORS.magenta,
},
{
name: 'WR威廉指标',
abbr: 'WR',
formula: 'WR = (最高价-收盘价)/(最高价-最低价)×(-100)',
description: '衡量市场的超买超卖程度,数值在-100到0之间。',
params: 'WR6、WR14',
usage: 'WR<-80超卖>-20超买从超买/超卖区回落时为反转信号',
color: INDICATOR_COLORS.green,
},
{
name: 'CCI商品通道指标',
abbr: 'CCI',
formula: 'TP = (最高+最低+收盘)/3\nCCI = (TP-MA(TP))/(0.015×平均绝对偏差)',
description: '测量价格偏离统计平均值的程度,适用于周期性波动。',
params: '周期14',
usage: 'CCI>+100超买<-100超卖突破±100为趋势启动信号',
color: INDICATOR_COLORS.orange,
},
{
name: 'BIAS乖离率',
abbr: 'BIAS',
formula: 'BIAS = (收盘价-MA)/MA × 100%',
description: '衡量价格偏离移动平均线的程度,用于判断回归。',
params: 'BIAS6、BIAS12、BIAS24',
usage: '正值过大表示超买,负值过大表示超卖;均值回归时机',
color: INDICATOR_COLORS.cyan,
},
],
};
const IndicatorCard: React.FC<{
indicator: typeof INDICATOR_DEFINITIONS.main[0];
}> = ({ indicator }) => {
return (
<Box
p={3}
bg="rgba(26, 32, 44, 0.6)"
borderRadius="md"
border="1px solid"
borderColor="rgba(212, 175, 55, 0.2)"
_hover={{ borderColor: 'rgba(212, 175, 55, 0.4)' }}
transition="all 0.2s"
>
<HStack justify="space-between" mb={2}>
<HStack spacing={2}>
<Badge
bg={indicator.color}
color="black"
fontSize="xs"
fontWeight="bold"
px={2}
py={0.5}
borderRadius="sm"
>
{indicator.abbr}
</Badge>
<Text fontSize="sm" fontWeight="bold" color="white">
{indicator.name}
</Text>
</HStack>
</HStack>
<VStack align="stretch" spacing={1.5} fontSize="xs">
<Box>
<Text color={darkGoldTheme.textMuted} mb={0.5}></Text>
<Text
color="rgba(255, 255, 255, 0.8)"
fontFamily="mono"
whiteSpace="pre-line"
bg="rgba(0, 0, 0, 0.3)"
px={2}
py={1}
borderRadius="sm"
>
{indicator.formula}
</Text>
</Box>
<Box>
<Text color={darkGoldTheme.textMuted} mb={0.5}></Text>
<Text color="rgba(255, 255, 255, 0.7)">{indicator.params}</Text>
</Box>
<Box>
<Text color={darkGoldTheme.textMuted} mb={0.5}>使</Text>
<Text color="rgba(255, 255, 255, 0.7)">{indicator.usage}</Text>
</Box>
</VStack>
</Box>
);
};
const IndicatorGuide: React.FC<IndicatorGuideProps> = ({ isOpen }) => {
return (
<Collapse in={isOpen} animateOpacity>
<Box
mt={3}
p={4}
bg="rgba(26, 32, 44, 0.8)"
borderRadius="lg"
border="1px solid"
borderColor="rgba(212, 175, 55, 0.3)"
backdropFilter="blur(10px)"
>
<VStack align="stretch" spacing={4}>
{/* 标题 */}
<HStack justify="space-between">
<Text
fontSize="md"
fontWeight="bold"
bgGradient={`linear(to-r, ${darkGoldTheme.gold}, ${darkGoldTheme.orange})`}
bgClip="text"
>
</Text>
<Text fontSize="xs" color={darkGoldTheme.textMuted}>
</Text>
</HStack>
{/* 主图指标 */}
<Box>
<HStack mb={2}>
<Badge
bg="rgba(212, 175, 55, 0.2)"
color={darkGoldTheme.gold}
fontSize="xs"
px={2}
py={0.5}
>
</Badge>
<Text fontSize="xs" color={darkGoldTheme.textMuted}>
K线图上显示
</Text>
</HStack>
<SimpleGrid columns={{ base: 1, md: 2 }} spacing={3}>
{INDICATOR_DEFINITIONS.main.map((indicator) => (
<IndicatorCard key={indicator.abbr} indicator={indicator} />
))}
</SimpleGrid>
</Box>
<Divider borderColor="rgba(212, 175, 55, 0.2)" />
{/* 副图指标 */}
<Box>
<HStack mb={2}>
<Badge
bg="rgba(212, 175, 55, 0.2)"
color={darkGoldTheme.gold}
fontSize="xs"
px={2}
py={0.5}
>
</Badge>
<Text fontSize="xs" color={darkGoldTheme.textMuted}>
K线图下方独立区域
</Text>
</HStack>
<SimpleGrid columns={{ base: 1, md: 2, lg: 3 }} spacing={3}>
{INDICATOR_DEFINITIONS.sub.map((indicator) => (
<IndicatorCard key={indicator.abbr} indicator={indicator} />
))}
</SimpleGrid>
</Box>
{/* 风险提示 */}
<Box
p={3}
bg="rgba(239, 68, 68, 0.1)"
borderRadius="md"
border="1px solid"
borderColor="rgba(239, 68, 68, 0.3)"
>
<Text fontSize="xs" color="rgba(239, 68, 68, 0.9)">
</Text>
</Box>
</VStack>
</Box>
</Collapse>
);
};
export default memo(IndicatorGuide);

View File

@@ -18,7 +18,7 @@ import {
MenuItem,
Tooltip,
} from '@chakra-ui/react';
import { BarChart2, TrendingUp, Calendar, LineChart, Activity, Pencil, RefreshCw, ChevronDown, Eye, EyeOff } from 'lucide-react';
import { BarChart2, TrendingUp, Calendar, LineChart, Activity, Pencil, RefreshCw, ChevronDown, Eye, EyeOff, HelpCircle } from 'lucide-react';
import { darkGoldTheme, PERIOD_OPTIONS } from '../../../../constants';
import type { IndicatorType, MainIndicatorType, DrawingType } from '../../../../utils/chartOptions';
@@ -59,6 +59,10 @@ export interface KLineToolbarProps {
onRemoveOverlayMetric: (metricId: string) => void;
stockDateRange?: { startDate: string; endDate: string };
// 指标说明
showIndicatorGuide: boolean;
onToggleIndicatorGuide: () => void;
// 分时模式
minuteData?: MinuteData | null;
minuteLoading: boolean;
@@ -84,6 +88,8 @@ const KLineToolbar: React.FC<KLineToolbarProps> = ({
onAddOverlayMetric,
onRemoveOverlayMetric,
stockDateRange,
showIndicatorGuide,
onToggleIndicatorGuide,
minuteData,
minuteLoading,
showOrderBook,
@@ -274,6 +280,20 @@ const KLineToolbar: React.FC<KLineToolbarProps> = ({
onRemoveMetric={onRemoveOverlayMetric}
stockDateRange={stockDateRange}
/>
{/* 指标说明按钮 */}
<Tooltip label={showIndicatorGuide ? '收起指标说明' : '展开指标说明'} placement="top" hasArrow>
<Button
size="sm"
variant="outline"
leftIcon={<HelpCircle size={14} />}
onClick={onToggleIndicatorGuide}
{...(showIndicatorGuide ? ACTIVE_BUTTON_STYLE : INACTIVE_BUTTON_STYLE)}
minW="90px"
>
</Button>
</Tooltip>
</>
)}

View File

@@ -9,3 +9,5 @@ export type { DailyKLineChartProps } from './DailyKLineChart';
export { default as MinuteChartWithOrderBook } from './MinuteChartWithOrderBook';
export type { MinuteChartWithOrderBookProps } from './MinuteChartWithOrderBook';
export { default as IndicatorGuide } from './IndicatorGuide';