更新Company页面的UI为FUI风格
This commit is contained in:
@@ -30,22 +30,23 @@ export interface Theme {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 黑金主题配置
|
// 黑金主题配置
|
||||||
|
// 注:文字颜色使用更亮的金色(#F4D03F)以提高对比度
|
||||||
export const THEME: Theme = {
|
export const THEME: Theme = {
|
||||||
bg: "gray.900",
|
bg: "gray.900",
|
||||||
cardBg: "gray.800",
|
cardBg: "gray.800",
|
||||||
tableBg: "gray.700",
|
tableBg: "gray.700",
|
||||||
tableHoverBg: "gray.600",
|
tableHoverBg: "gray.600",
|
||||||
gold: "#D4AF37",
|
gold: "#F4D03F", // 亮黄金色(用于文字,对比度更好)
|
||||||
goldLight: "#F0D78C",
|
goldLight: "#F0D78C", // 浅金色(用于次要文字)
|
||||||
textPrimary: "white",
|
textPrimary: "white",
|
||||||
textSecondary: "gray.400",
|
textSecondary: "gray.400",
|
||||||
border: "rgba(212, 175, 55, 0.3)",
|
border: "rgba(212, 175, 55, 0.3)", // 边框保持原色
|
||||||
tabSelected: {
|
tabSelected: {
|
||||||
bg: "#D4AF37",
|
bg: "#D4AF37", // 选中背景保持深金色
|
||||||
color: "gray.900",
|
color: "gray.900",
|
||||||
},
|
},
|
||||||
tabUnselected: {
|
tabUnselected: {
|
||||||
color: "#D4AF37",
|
color: "#F4D03F", // 未选中使用亮金色
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -11,12 +11,12 @@ import { Box, HStack, VStack, Text, Badge, Tag, TagLabel } from '@chakra-ui/reac
|
|||||||
import { formatPercentage, formatBusinessRevenue } from '@utils/priceFormatters';
|
import { formatPercentage, formatBusinessRevenue } from '@utils/priceFormatters';
|
||||||
import type { BusinessTreeItemProps } from '../types';
|
import type { BusinessTreeItemProps } from '../types';
|
||||||
|
|
||||||
// 黑金主题配置
|
// 黑金主题配置(使用更亮的金色提高对比度)
|
||||||
const THEME = {
|
const THEME = {
|
||||||
bg: 'gray.700',
|
bg: 'gray.700',
|
||||||
gold: '#D4AF37',
|
gold: '#F4D03F', // 亮金色
|
||||||
goldLight: '#F0D78C',
|
goldLight: '#F0D78C',
|
||||||
textPrimary: '#D4AF37',
|
textPrimary: '#F4D03F', // 亮金色(提高对比度)
|
||||||
textSecondary: 'gray.400',
|
textSecondary: 'gray.400',
|
||||||
border: 'rgba(212, 175, 55, 0.5)',
|
border: 'rgba(212, 175, 55, 0.5)',
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ import React, { memo } from 'react';
|
|||||||
import { HStack, VStack, Box, Text, Icon, Badge } from '@chakra-ui/react';
|
import { HStack, VStack, Box, Text, Icon, Badge } from '@chakra-ui/react';
|
||||||
import { FaArrowRight } from 'react-icons/fa';
|
import { FaArrowRight } from 'react-icons/fa';
|
||||||
|
|
||||||
// 黑金主题配置
|
// 黑金主题配置(使用更亮的金色提高对比度)
|
||||||
const THEME = {
|
const THEME = {
|
||||||
gold: '#D4AF37',
|
gold: '#F4D03F',
|
||||||
textSecondary: 'gray.400',
|
textSecondary: 'gray.400',
|
||||||
upstream: {
|
upstream: {
|
||||||
active: 'orange.500',
|
active: 'orange.500',
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ import {
|
|||||||
Tab,
|
Tab,
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
|
|
||||||
// 黑金主题配置
|
// 黑金主题配置(使用更亮的金色提高对比度)
|
||||||
const THEME = {
|
const THEME = {
|
||||||
gold: '#D4AF37',
|
gold: '#F4D03F',
|
||||||
textPrimary: '#D4AF37',
|
textPrimary: '#F4D03F',
|
||||||
textSecondary: 'gray.400',
|
textSecondary: 'gray.400',
|
||||||
inputBg: 'gray.700',
|
inputBg: 'gray.700',
|
||||||
inputBorder: 'gray.600',
|
inputBorder: 'gray.600',
|
||||||
|
|||||||
@@ -27,9 +27,9 @@ import type { BusinessSegment } from '../types';
|
|||||||
const THEME = {
|
const THEME = {
|
||||||
cardBg: 'gray.800',
|
cardBg: 'gray.800',
|
||||||
innerCardBg: 'gray.700',
|
innerCardBg: 'gray.700',
|
||||||
gold: '#D4AF37',
|
gold: '#F4D03F',
|
||||||
goldLight: '#F0D78C',
|
goldLight: '#F0D78C',
|
||||||
textPrimary: '#D4AF37',
|
textPrimary: '#F4D03F',
|
||||||
textSecondary: 'gray.400',
|
textSecondary: 'gray.400',
|
||||||
border: 'rgba(212, 175, 55, 0.3)',
|
border: 'rgba(212, 175, 55, 0.3)',
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ import type { BusinessStructure } from '../types';
|
|||||||
// 黑金主题配置
|
// 黑金主题配置
|
||||||
const THEME = {
|
const THEME = {
|
||||||
cardBg: 'gray.800',
|
cardBg: 'gray.800',
|
||||||
gold: '#D4AF37',
|
gold: '#F4D03F',
|
||||||
textPrimary: '#D4AF37',
|
textPrimary: '#F4D03F',
|
||||||
border: 'rgba(212, 175, 55, 0.3)',
|
border: 'rgba(212, 175, 55, 0.3)',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -15,13 +15,13 @@ import type { IconType } from 'react-icons';
|
|||||||
// ==================== 主题常量 ====================
|
// ==================== 主题常量 ====================
|
||||||
|
|
||||||
export const THEME = {
|
export const THEME = {
|
||||||
// 深色背景区域(核心定位)
|
// 深色背景区域(核心定位)- 使用更亮的金色提高对比度
|
||||||
dark: {
|
dark: {
|
||||||
bg: '#1A202C',
|
bg: '#1A202C',
|
||||||
cardBg: '#252D3A',
|
cardBg: '#252D3A',
|
||||||
border: '#C9A961',
|
border: '#E8C14D',
|
||||||
borderGradient: 'linear-gradient(90deg, #C9A961, #8B7355)',
|
borderGradient: 'linear-gradient(90deg, #E8C14D, #A08040)',
|
||||||
titleColor: '#C9A961',
|
titleColor: '#E8C14D',
|
||||||
textColor: '#E2E8F0',
|
textColor: '#E2E8F0',
|
||||||
subtextColor: '#A0AEC0',
|
subtextColor: '#A0AEC0',
|
||||||
},
|
},
|
||||||
@@ -29,11 +29,11 @@ export const THEME = {
|
|||||||
light: {
|
light: {
|
||||||
bg: '#1E2530',
|
bg: '#1E2530',
|
||||||
cardBg: '#252D3A',
|
cardBg: '#252D3A',
|
||||||
titleColor: '#C9A961',
|
titleColor: '#E8C14D',
|
||||||
textColor: '#E2E8F0',
|
textColor: '#E2E8F0',
|
||||||
subtextColor: '#A0AEC0',
|
subtextColor: '#A0AEC0',
|
||||||
tagBg: 'rgba(201, 169, 97, 0.15)',
|
tagBg: 'rgba(232, 193, 77, 0.15)',
|
||||||
tagColor: '#C9A961',
|
tagColor: '#E8C14D',
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
|||||||
@@ -31,9 +31,9 @@ import type { KeyFactors } from '../types';
|
|||||||
const THEME = {
|
const THEME = {
|
||||||
bg: '#1A202C',
|
bg: '#1A202C',
|
||||||
cardBg: '#252D3A',
|
cardBg: '#252D3A',
|
||||||
border: '#C9A961',
|
border: '#E8C14D',
|
||||||
borderGradient: 'linear-gradient(90deg, #C9A961, #8B7355)',
|
borderGradient: 'linear-gradient(90deg, #E8C14D, #A08040)',
|
||||||
titleColor: '#C9A961',
|
titleColor: '#E8C14D',
|
||||||
textColor: '#E2E8F0',
|
textColor: '#E2E8F0',
|
||||||
subtextColor: '#A0AEC0',
|
subtextColor: '#A0AEC0',
|
||||||
} as const;
|
} as const;
|
||||||
|
|||||||
@@ -24,9 +24,9 @@ import type { DevelopmentTimeline } from '../types';
|
|||||||
const THEME = {
|
const THEME = {
|
||||||
bg: '#1A202C',
|
bg: '#1A202C',
|
||||||
cardBg: '#252D3A',
|
cardBg: '#252D3A',
|
||||||
border: '#C9A961',
|
border: '#E8C14D',
|
||||||
borderGradient: 'linear-gradient(90deg, #C9A961, #8B7355)',
|
borderGradient: 'linear-gradient(90deg, #E8C14D, #A08040)',
|
||||||
titleColor: '#C9A961',
|
titleColor: '#E8C14D',
|
||||||
textColor: '#E2E8F0',
|
textColor: '#E2E8F0',
|
||||||
subtextColor: '#A0AEC0',
|
subtextColor: '#A0AEC0',
|
||||||
} as const;
|
} as const;
|
||||||
|
|||||||
@@ -34,9 +34,9 @@ import type { ValueChainData, ValueChainNode } from '../types';
|
|||||||
// 黑金主题配置
|
// 黑金主题配置
|
||||||
const THEME = {
|
const THEME = {
|
||||||
cardBg: 'gray.800',
|
cardBg: 'gray.800',
|
||||||
gold: '#D4AF37',
|
gold: '#F4D03F',
|
||||||
goldLight: '#F0D78C',
|
goldLight: '#F0D78C',
|
||||||
textPrimary: '#D4AF37',
|
textPrimary: '#F4D03F',
|
||||||
textSecondary: 'gray.400',
|
textSecondary: 'gray.400',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ import type { ValueChainNodeCardProps, RelatedCompany } from '../../types';
|
|||||||
// 黑金主题配置
|
// 黑金主题配置
|
||||||
const THEME = {
|
const THEME = {
|
||||||
cardBg: 'gray.700',
|
cardBg: 'gray.700',
|
||||||
gold: '#D4AF37',
|
gold: '#F4D03F',
|
||||||
goldLight: '#F0D78C',
|
goldLight: '#F0D78C',
|
||||||
textPrimary: 'white',
|
textPrimary: 'white',
|
||||||
textSecondary: 'gray.400',
|
textSecondary: 'gray.400',
|
||||||
|
|||||||
@@ -38,22 +38,22 @@ import {
|
|||||||
} from "react-icons/fa";
|
} from "react-icons/fa";
|
||||||
import { getEventDetailUrl } from "@/utils/idEncoder";
|
import { getEventDetailUrl } from "@/utils/idEncoder";
|
||||||
|
|
||||||
// 黑金主题配色
|
// 黑金主题配色(文字使用更亮的金色提高对比度)
|
||||||
const THEME_PRESETS = {
|
const THEME_PRESETS = {
|
||||||
blackGold: {
|
blackGold: {
|
||||||
bg: "#0A0E17",
|
bg: "#0A0E17",
|
||||||
cardBg: "#1A1F2E",
|
cardBg: "#1A1F2E",
|
||||||
cardHoverBg: "#212633",
|
cardHoverBg: "#212633",
|
||||||
cardBorder: "rgba(212, 175, 55, 0.2)",
|
cardBorder: "rgba(212, 175, 55, 0.2)",
|
||||||
cardHoverBorder: "#D4AF37",
|
cardHoverBorder: "#F4D03F", // 亮金色
|
||||||
textPrimary: "#E8E9ED",
|
textPrimary: "#E8E9ED",
|
||||||
textSecondary: "#A0A4B8",
|
textSecondary: "#A0A4B8",
|
||||||
textMuted: "#6B7280",
|
textMuted: "#6B7280",
|
||||||
gold: "#D4AF37",
|
gold: "#F4D03F", // 亮金色(用于文字)
|
||||||
goldLight: "#FFD54F",
|
goldLight: "#FFD54F",
|
||||||
inputBg: "#151922",
|
inputBg: "#151922",
|
||||||
inputBorder: "#2D3748",
|
inputBorder: "#2D3748",
|
||||||
buttonBg: "#D4AF37",
|
buttonBg: "#D4AF37", // 按钮背景保持深金色
|
||||||
buttonText: "#0A0E17",
|
buttonText: "#0A0E17",
|
||||||
buttonHoverBg: "#FFD54F",
|
buttonHoverBg: "#FFD54F",
|
||||||
badgeS: { bg: "rgba(255, 195, 0, 0.2)", color: "#FFD54F" },
|
badgeS: { bg: "rgba(255, 195, 0, 0.2)", color: "#FFD54F" },
|
||||||
@@ -61,8 +61,8 @@ const THEME_PRESETS = {
|
|||||||
badgeB: { bg: "rgba(59, 130, 246, 0.2)", color: "#60A5FA" },
|
badgeB: { bg: "rgba(59, 130, 246, 0.2)", color: "#60A5FA" },
|
||||||
badgeC: { bg: "rgba(107, 114, 128, 0.2)", color: "#9CA3AF" },
|
badgeC: { bg: "rgba(107, 114, 128, 0.2)", color: "#9CA3AF" },
|
||||||
tagBg: "rgba(212, 175, 55, 0.15)",
|
tagBg: "rgba(212, 175, 55, 0.15)",
|
||||||
tagColor: "#D4AF37",
|
tagColor: "#F4D03F", // 亮金色
|
||||||
spinnerColor: "#D4AF37",
|
spinnerColor: "#F4D03F", // 亮金色
|
||||||
},
|
},
|
||||||
default: {
|
default: {
|
||||||
bg: "white",
|
bg: "white",
|
||||||
|
|||||||
@@ -10,17 +10,18 @@ import type { Shareholder } from "../../types";
|
|||||||
import { THEME } from "../../BasicInfoTab/config";
|
import { THEME } from "../../BasicInfoTab/config";
|
||||||
|
|
||||||
// antd 表格黑金主题配置
|
// antd 表格黑金主题配置
|
||||||
|
// 使用更亮的金色以提高对比度
|
||||||
const TABLE_THEME = {
|
const TABLE_THEME = {
|
||||||
token: {
|
token: {
|
||||||
colorBgContainer: "#2D3748", // gray.700
|
colorBgContainer: "#2D3748", // gray.700
|
||||||
colorText: "white",
|
colorText: "white",
|
||||||
colorTextHeading: "#D4AF37", // 金色
|
colorTextHeading: "#F4D03F", // 亮金色(提高对比度)
|
||||||
colorBorderSecondary: "rgba(212, 175, 55, 0.3)",
|
colorBorderSecondary: "rgba(212, 175, 55, 0.3)",
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
Table: {
|
Table: {
|
||||||
headerBg: "#1A202C", // gray.900
|
headerBg: "#1A202C", // gray.900
|
||||||
headerColor: "#D4AF37", // 金色
|
headerColor: "#F4D03F", // 亮金色(提高对比度)
|
||||||
rowHoverBg: "rgba(212, 175, 55, 0.15)", // 金色半透明,文字更清晰
|
rowHoverBg: "rgba(212, 175, 55, 0.15)", // 金色半透明,文字更清晰
|
||||||
borderColor: "rgba(212, 175, 55, 0.2)",
|
borderColor: "rgba(212, 175, 55, 0.2)",
|
||||||
},
|
},
|
||||||
@@ -135,7 +136,7 @@ const ShareholdersTable: React.FC<ShareholdersTableProps> = ({
|
|||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
render: (name: string) => (
|
render: (name: string) => (
|
||||||
<Tooltip title={name}>
|
<Tooltip title={name}>
|
||||||
<span style={{ fontWeight: 500, color: "#D4AF37" }}>{name}</span>
|
<span style={{ fontWeight: 500, color: "#F4D03F" }}>{name}</span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@@ -158,7 +159,7 @@ const ShareholdersTable: React.FC<ShareholdersTableProps> = ({
|
|||||||
responsive: ["md"],
|
responsive: ["md"],
|
||||||
sorter: (a: Shareholder, b: Shareholder) => (a.holding_shares || 0) - (b.holding_shares || 0),
|
sorter: (a: Shareholder, b: Shareholder) => (a.holding_shares || 0) - (b.holding_shares || 0),
|
||||||
render: (shares: number) => (
|
render: (shares: number) => (
|
||||||
<span style={{ color: "#D4AF37" }}>{formatShares(shares)}</span>
|
<span style={{ color: "#F4D03F" }}>{formatShares(shares)}</span>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// src/views/Company/components/MarketDataView/components/panels/TradeDataPanel/KLineModule.tsx
|
// src/views/Company/components/MarketDataView/components/panels/TradeDataPanel/KLineModule.tsx
|
||||||
// K线模块 - 日K线/分时图切换展示(黑金主题 + 专业技术指标 + 商品数据叠加)
|
// K线模块 - 日K线/分时图切换展示(黑金主题 + 专业技术指标 + 商品数据叠加 + 分时盘口)
|
||||||
|
|
||||||
import React, { useState, useMemo, useCallback } from 'react';
|
import React, { useState, useMemo, useCallback, useEffect } from 'react';
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Text,
|
Text,
|
||||||
@@ -20,11 +20,17 @@ import {
|
|||||||
MenuItem,
|
MenuItem,
|
||||||
MenuDivider,
|
MenuDivider,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
|
Grid,
|
||||||
|
GridItem,
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import { RepeatIcon, InfoIcon, ChevronDownIcon, ViewIcon, ViewOffIcon } from '@chakra-ui/icons';
|
import { RepeatIcon, InfoIcon, ChevronDownIcon, ViewIcon, ViewOffIcon } from '@chakra-ui/icons';
|
||||||
import { BarChart2, Clock, TrendingUp, Calendar, LineChart, Activity, Pencil } from 'lucide-react';
|
import { BarChart2, Clock, TrendingUp, Calendar, LineChart, Activity, Pencil } from 'lucide-react';
|
||||||
import ReactECharts from 'echarts-for-react';
|
import ReactECharts from 'echarts-for-react';
|
||||||
|
|
||||||
|
// 导入实时行情 Hook 和五档盘口组件
|
||||||
|
import { useRealtimeQuote } from '@views/StockOverview/components/FlexScreen/hooks';
|
||||||
|
import OrderBookPanel from '@views/StockOverview/components/FlexScreen/components/OrderBookPanel';
|
||||||
|
|
||||||
import { darkGoldTheme, PERIOD_OPTIONS } from '../../../constants';
|
import { darkGoldTheme, PERIOD_OPTIONS } from '../../../constants';
|
||||||
import {
|
import {
|
||||||
getKLineDarkGoldOption,
|
getKLineDarkGoldOption,
|
||||||
@@ -90,6 +96,7 @@ const KLineModule: React.FC<KLineModuleProps> = ({
|
|||||||
onChartClick,
|
onChartClick,
|
||||||
selectedPeriod,
|
selectedPeriod,
|
||||||
onPeriodChange,
|
onPeriodChange,
|
||||||
|
stockCode,
|
||||||
}) => {
|
}) => {
|
||||||
const [mode, setMode] = useState<ChartMode>('daily');
|
const [mode, setMode] = useState<ChartMode>('daily');
|
||||||
const [subIndicator, setSubIndicator] = useState<IndicatorType>('MACD');
|
const [subIndicator, setSubIndicator] = useState<IndicatorType>('MACD');
|
||||||
@@ -97,8 +104,34 @@ const KLineModule: React.FC<KLineModuleProps> = ({
|
|||||||
const [showAnalysis, setShowAnalysis] = useState<boolean>(true);
|
const [showAnalysis, setShowAnalysis] = useState<boolean>(true);
|
||||||
const [drawingType, setDrawingType] = useState<DrawingType>('NONE');
|
const [drawingType, setDrawingType] = useState<DrawingType>('NONE');
|
||||||
const [overlayMetrics, setOverlayMetrics] = useState<OverlayMetricData[]>([]);
|
const [overlayMetrics, setOverlayMetrics] = useState<OverlayMetricData[]>([]);
|
||||||
|
const [showOrderBook, setShowOrderBook] = useState<boolean>(true);
|
||||||
const hasMinuteData = minuteData && minuteData.data && minuteData.data.length > 0;
|
const hasMinuteData = minuteData && minuteData.data && minuteData.data.length > 0;
|
||||||
|
|
||||||
|
// 实时行情数据(用于五档盘口)
|
||||||
|
const subscribedCodes = useMemo(() => {
|
||||||
|
if (!stockCode || mode !== 'minute') return [];
|
||||||
|
return [stockCode];
|
||||||
|
}, [stockCode, mode]);
|
||||||
|
|
||||||
|
const { quotes, connected } = useRealtimeQuote(subscribedCodes);
|
||||||
|
|
||||||
|
// 获取当前股票的行情数据
|
||||||
|
const currentQuote = useMemo(() => {
|
||||||
|
if (!stockCode) return null;
|
||||||
|
// 尝试不同的代码格式
|
||||||
|
return quotes[stockCode] || quotes[`${stockCode}.SH`] || quotes[`${stockCode}.SZ`] || null;
|
||||||
|
}, [quotes, stockCode]);
|
||||||
|
|
||||||
|
// 判断是否在交易时间
|
||||||
|
const isInTradingHours = useMemo(() => {
|
||||||
|
const now = new Date();
|
||||||
|
const hours = now.getHours();
|
||||||
|
const minutes = now.getMinutes();
|
||||||
|
const totalMinutes = hours * 60 + minutes;
|
||||||
|
// 9:15-11:30 或 13:00-15:00
|
||||||
|
return (totalMinutes >= 555 && totalMinutes <= 690) || (totalMinutes >= 780 && totalMinutes <= 900);
|
||||||
|
}, []);
|
||||||
|
|
||||||
// 计算股票数据的日期范围(用于查询商品数据)
|
// 计算股票数据的日期范围(用于查询商品数据)
|
||||||
const stockDateRange = useMemo(() => {
|
const stockDateRange = useMemo(() => {
|
||||||
if (tradeData.length === 0) return undefined;
|
if (tradeData.length === 0) return undefined;
|
||||||
@@ -369,19 +402,35 @@ const KLineModule: React.FC<KLineModuleProps> = ({
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* 分时模式下的刷新按钮 */}
|
{/* 分时模式下的控制按钮 */}
|
||||||
{mode === 'minute' && (
|
{mode === 'minute' && (
|
||||||
<Button
|
<>
|
||||||
leftIcon={<RepeatIcon />}
|
{/* 显示/隐藏盘口 */}
|
||||||
size="sm"
|
<Tooltip label={showOrderBook ? '隐藏盘口' : '显示盘口'} placement="top" hasArrow>
|
||||||
variant="outline"
|
<Button
|
||||||
onClick={onLoadMinuteData}
|
size="sm"
|
||||||
isLoading={minuteLoading}
|
variant="outline"
|
||||||
loadingText="获取中"
|
onClick={() => setShowOrderBook(!showOrderBook)}
|
||||||
{...inactiveButtonStyle}
|
{...(showOrderBook ? activeButtonStyle : inactiveButtonStyle)}
|
||||||
>
|
minW="80px"
|
||||||
刷新
|
>
|
||||||
</Button>
|
{showOrderBook ? '隐藏盘口' : '显示盘口'}
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
|
{/* 刷新按钮 */}
|
||||||
|
<Button
|
||||||
|
leftIcon={<RepeatIcon />}
|
||||||
|
size="sm"
|
||||||
|
variant="outline"
|
||||||
|
onClick={onLoadMinuteData}
|
||||||
|
isLoading={minuteLoading}
|
||||||
|
loadingText="获取中"
|
||||||
|
{...inactiveButtonStyle}
|
||||||
|
>
|
||||||
|
刷新
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* 模式切换按钮组 */}
|
{/* 模式切换按钮组 */}
|
||||||
@@ -424,7 +473,7 @@ const KLineModule: React.FC<KLineModuleProps> = ({
|
|||||||
<EmptyState title="暂无日K线数据" description="该股票暂无交易数据" />
|
<EmptyState title="暂无日K线数据" description="该股票暂无交易数据" />
|
||||||
)
|
)
|
||||||
) : (
|
) : (
|
||||||
// 分时走势图
|
// 分时走势图 + 五档盘口
|
||||||
minuteLoading ? (
|
minuteLoading ? (
|
||||||
<Center h="450px">
|
<Center h="450px">
|
||||||
<VStack spacing={4}>
|
<VStack spacing={4}>
|
||||||
@@ -441,15 +490,115 @@ const KLineModule: React.FC<KLineModuleProps> = ({
|
|||||||
</VStack>
|
</VStack>
|
||||||
</Center>
|
</Center>
|
||||||
) : hasMinuteData ? (
|
) : hasMinuteData ? (
|
||||||
<Box h="450px">
|
<Grid templateColumns={showOrderBook ? '1fr 220px' : '1fr'} gap={4} h="450px">
|
||||||
<ReactECharts
|
{/* 分时图表 */}
|
||||||
option={getMinuteKLineDarkGoldOption(minuteData)}
|
<GridItem>
|
||||||
style={{ height: '100%', width: '100%' }}
|
<Box h="100%">
|
||||||
theme="dark"
|
<ReactECharts
|
||||||
notMerge={true}
|
option={getMinuteKLineDarkGoldOption(minuteData)}
|
||||||
opts={{ renderer: 'canvas' }}
|
style={{ height: '100%', width: '100%' }}
|
||||||
/>
|
theme="dark"
|
||||||
</Box>
|
notMerge={true}
|
||||||
|
opts={{ renderer: 'canvas' }}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</GridItem>
|
||||||
|
|
||||||
|
{/* 五档盘口 */}
|
||||||
|
{showOrderBook && (
|
||||||
|
<GridItem>
|
||||||
|
<Box
|
||||||
|
h="100%"
|
||||||
|
bg="rgba(0, 0, 0, 0.3)"
|
||||||
|
borderRadius="lg"
|
||||||
|
border="1px solid"
|
||||||
|
borderColor={darkGoldTheme.border}
|
||||||
|
p={3}
|
||||||
|
overflowY="auto"
|
||||||
|
>
|
||||||
|
{/* 盘口标题 */}
|
||||||
|
<HStack justify="space-between" mb={3}>
|
||||||
|
<Text fontSize="sm" fontWeight="bold" color={darkGoldTheme.gold}>
|
||||||
|
五档盘口
|
||||||
|
</Text>
|
||||||
|
{/* 连接状态指示 */}
|
||||||
|
<HStack spacing={1}>
|
||||||
|
{isInTradingHours && (
|
||||||
|
<Badge
|
||||||
|
bg={connected.SSE || connected.SZSE ? 'green.500' : 'gray.500'}
|
||||||
|
color="white"
|
||||||
|
fontSize="2xs"
|
||||||
|
px={1}
|
||||||
|
>
|
||||||
|
{connected.SSE || connected.SZSE ? '实时' : '离线'}
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
|
</HStack>
|
||||||
|
</HStack>
|
||||||
|
|
||||||
|
{/* 当前价格信息 */}
|
||||||
|
{currentQuote && (
|
||||||
|
<VStack spacing={1} mb={3} align="stretch">
|
||||||
|
<HStack justify="space-between">
|
||||||
|
<Text fontSize="xs" color={darkGoldTheme.textMuted}>当前价</Text>
|
||||||
|
<Text
|
||||||
|
fontSize="lg"
|
||||||
|
fontWeight="bold"
|
||||||
|
color={
|
||||||
|
currentQuote.changePct > 0 ? '#ff4d4d' :
|
||||||
|
currentQuote.changePct < 0 ? '#22c55e' :
|
||||||
|
darkGoldTheme.textPrimary
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{currentQuote.price?.toFixed(2) || '-'}
|
||||||
|
</Text>
|
||||||
|
</HStack>
|
||||||
|
<HStack justify="space-between">
|
||||||
|
<Text fontSize="xs" color={darkGoldTheme.textMuted}>涨跌幅</Text>
|
||||||
|
<Text
|
||||||
|
fontSize="sm"
|
||||||
|
color={
|
||||||
|
currentQuote.changePct > 0 ? '#ff4d4d' :
|
||||||
|
currentQuote.changePct < 0 ? '#22c55e' :
|
||||||
|
darkGoldTheme.textMuted
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{currentQuote.changePct > 0 ? '+' : ''}{currentQuote.changePct?.toFixed(2) || '0.00'}%
|
||||||
|
</Text>
|
||||||
|
</HStack>
|
||||||
|
</VStack>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* 五档盘口面板 */}
|
||||||
|
{currentQuote && (currentQuote.bidPrices?.length > 0 || currentQuote.askPrices?.length > 0) ? (
|
||||||
|
<OrderBookPanel
|
||||||
|
bidPrices={currentQuote.bidPrices || []}
|
||||||
|
bidVolumes={currentQuote.bidVolumes || []}
|
||||||
|
askPrices={currentQuote.askPrices || []}
|
||||||
|
askVolumes={currentQuote.askVolumes || []}
|
||||||
|
prevClose={currentQuote.prevClose}
|
||||||
|
upperLimit={'upperLimit' in currentQuote ? currentQuote.upperLimit : undefined}
|
||||||
|
lowerLimit={'lowerLimit' in currentQuote ? currentQuote.lowerLimit : undefined}
|
||||||
|
defaultLevels={5}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Center h="200px">
|
||||||
|
<VStack spacing={2}>
|
||||||
|
<Text fontSize="xs" color={darkGoldTheme.textMuted}>
|
||||||
|
{isInTradingHours ? '获取盘口数据中...' : '非交易时间'}
|
||||||
|
</Text>
|
||||||
|
{!isInTradingHours && (
|
||||||
|
<Text fontSize="2xs" color={darkGoldTheme.textMuted}>
|
||||||
|
交易时间: 9:30-11:30, 13:00-15:00
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
</VStack>
|
||||||
|
</Center>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</GridItem>
|
||||||
|
)}
|
||||||
|
</Grid>
|
||||||
) : (
|
) : (
|
||||||
<EmptyState title="暂无分时数据" description="点击刷新按钮获取当日分时数据" />
|
<EmptyState title="暂无分时数据" description="点击刷新按钮获取当日分时数据" />
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ const MetricOverlaySearch: React.FC<MetricOverlaySearchProps> = ({
|
|||||||
|
|
||||||
setIsSearching(true);
|
setIsSearching(true);
|
||||||
try {
|
try {
|
||||||
const response = await searchMetrics(query, undefined, undefined, 20);
|
const response = await searchMetrics(query, undefined, '日', 20);
|
||||||
setSearchResults(response.results || []);
|
setSearchResults(response.results || []);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Search metrics failed:', error);
|
console.error('Search metrics failed:', error);
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ export interface TradeDataPanelProps {
|
|||||||
onChartClick: (params: { seriesName?: string; data?: [number, number] }) => void;
|
onChartClick: (params: { seriesName?: string; data?: [number, number] }) => void;
|
||||||
selectedPeriod?: number;
|
selectedPeriod?: number;
|
||||||
onPeriodChange?: (period: number) => void;
|
onPeriodChange?: (period: number) => void;
|
||||||
|
stockCode?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TradeDataPanel: React.FC<TradeDataPanelProps> = ({
|
const TradeDataPanel: React.FC<TradeDataPanelProps> = ({
|
||||||
@@ -28,6 +29,7 @@ const TradeDataPanel: React.FC<TradeDataPanelProps> = ({
|
|||||||
onChartClick,
|
onChartClick,
|
||||||
selectedPeriod,
|
selectedPeriod,
|
||||||
onPeriodChange,
|
onPeriodChange,
|
||||||
|
stockCode,
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<KLineModule
|
<KLineModule
|
||||||
@@ -40,6 +42,7 @@ const TradeDataPanel: React.FC<TradeDataPanelProps> = ({
|
|||||||
onChartClick={onChartClick}
|
onChartClick={onChartClick}
|
||||||
selectedPeriod={selectedPeriod}
|
selectedPeriod={selectedPeriod}
|
||||||
onPeriodChange={onPeriodChange}
|
onPeriodChange={onPeriodChange}
|
||||||
|
stockCode={stockCode}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -153,6 +153,7 @@ const MarketDataView: React.FC<MarketDataViewProps> = ({ stockCode: propStockCod
|
|||||||
onChartClick={handleChartClick}
|
onChartClick={handleChartClick}
|
||||||
selectedPeriod={selectedPeriod}
|
selectedPeriod={selectedPeriod}
|
||||||
onPeriodChange={setSelectedPeriod}
|
onPeriodChange={setSelectedPeriod}
|
||||||
|
stockCode={stockCode}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
@@ -299,6 +299,7 @@ export interface KLineModuleProps {
|
|||||||
onChartClick: (params: { seriesName?: string; data?: [number, number] }) => void;
|
onChartClick: (params: { seriesName?: string; data?: [number, number] }) => void;
|
||||||
selectedPeriod?: number;
|
selectedPeriod?: number;
|
||||||
onPeriodChange?: (period: number) => void;
|
onPeriodChange?: (period: number) => void;
|
||||||
|
stockCode?: string; // 股票代码,用于获取实时盘口数据
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user