style(Panels): 应用黑金主题样式
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
// src/views/Company/components/MarketDataView/components/panels/BigDealPanel.tsx
|
// src/views/Company/components/MarketDataView/components/panels/BigDealPanel.tsx
|
||||||
// 大宗交易面板 - 大宗交易记录表格
|
// 大宗交易面板 - 黑金主题
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {
|
import {
|
||||||
@@ -12,18 +12,15 @@ import {
|
|||||||
Th,
|
Th,
|
||||||
Td,
|
Td,
|
||||||
TableContainer,
|
TableContainer,
|
||||||
CardBody,
|
|
||||||
CardHeader,
|
|
||||||
Center,
|
Center,
|
||||||
Badge,
|
|
||||||
VStack,
|
VStack,
|
||||||
HStack,
|
HStack,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
Heading,
|
Heading,
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
|
|
||||||
import ThemedCard from '../ThemedCard';
|
|
||||||
import { formatNumber } from '../../utils/formatUtils';
|
import { formatNumber } from '../../utils/formatUtils';
|
||||||
|
import { darkGoldTheme } from '../../constants';
|
||||||
import type { Theme, BigDealData } from '../../types';
|
import type { Theme, BigDealData } from '../../types';
|
||||||
|
|
||||||
export interface BigDealPanelProps {
|
export interface BigDealPanelProps {
|
||||||
@@ -31,69 +28,116 @@ export interface BigDealPanelProps {
|
|||||||
bigDealData: BigDealData;
|
bigDealData: BigDealData;
|
||||||
}
|
}
|
||||||
|
|
||||||
const BigDealPanel: React.FC<BigDealPanelProps> = ({ theme, bigDealData }) => {
|
// 黑金卡片样式
|
||||||
|
const darkGoldCardStyle = {
|
||||||
|
bg: darkGoldTheme.bgCard,
|
||||||
|
border: '1px solid',
|
||||||
|
borderColor: darkGoldTheme.border,
|
||||||
|
borderRadius: 'xl',
|
||||||
|
boxShadow: '0 4px 20px rgba(0, 0, 0, 0.3)',
|
||||||
|
transition: 'all 0.3s ease',
|
||||||
|
_hover: {
|
||||||
|
borderColor: darkGoldTheme.borderHover,
|
||||||
|
boxShadow: '0 8px 30px rgba(212, 175, 55, 0.15)',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// 黑金徽章样式
|
||||||
|
const DarkGoldBadge: React.FC<{ children: React.ReactNode; variant?: 'gold' | 'orange' | 'green' | 'purple' }> = ({
|
||||||
|
children,
|
||||||
|
variant = 'gold',
|
||||||
|
}) => {
|
||||||
|
const colors = {
|
||||||
|
gold: { bg: 'rgba(212, 175, 55, 0.15)', color: darkGoldTheme.gold },
|
||||||
|
orange: { bg: 'rgba(255, 149, 0, 0.15)', color: darkGoldTheme.orange },
|
||||||
|
green: { bg: 'rgba(0, 200, 81, 0.15)', color: darkGoldTheme.green },
|
||||||
|
purple: { bg: 'rgba(160, 120, 220, 0.15)', color: '#A078DC' },
|
||||||
|
};
|
||||||
|
const style = colors[variant];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ThemedCard theme={theme}>
|
<Box
|
||||||
<CardHeader>
|
px={2}
|
||||||
<Heading size="md" color={theme.textSecondary}>
|
py={1}
|
||||||
|
bg={style.bg}
|
||||||
|
color={style.color}
|
||||||
|
borderRadius="md"
|
||||||
|
fontSize="xs"
|
||||||
|
fontWeight="medium"
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const BigDealPanel: React.FC<BigDealPanelProps> = ({ bigDealData }) => {
|
||||||
|
return (
|
||||||
|
<Box {...darkGoldCardStyle} overflow="hidden">
|
||||||
|
<Box p={4} borderBottom="1px solid" borderColor={darkGoldTheme.border}>
|
||||||
|
<Heading size="md" color={darkGoldTheme.gold}>
|
||||||
大宗交易记录
|
大宗交易记录
|
||||||
</Heading>
|
</Heading>
|
||||||
</CardHeader>
|
</Box>
|
||||||
<CardBody>
|
<Box p={4}>
|
||||||
{bigDealData?.daily_stats && bigDealData.daily_stats.length > 0 ? (
|
{bigDealData?.daily_stats && bigDealData.daily_stats.length > 0 ? (
|
||||||
<VStack spacing={6} align="stretch">
|
<VStack spacing={4} align="stretch">
|
||||||
{bigDealData.daily_stats.map((dayStats, idx) => (
|
{bigDealData.daily_stats.map((dayStats, idx) => (
|
||||||
<Box
|
<Box
|
||||||
key={idx}
|
key={idx}
|
||||||
p={4}
|
p={4}
|
||||||
bg={theme.bgDark}
|
bg="rgba(212, 175, 55, 0.05)"
|
||||||
borderRadius="lg"
|
borderRadius="lg"
|
||||||
border="1px solid"
|
border="1px solid"
|
||||||
borderColor={theme.border}
|
borderColor="rgba(212, 175, 55, 0.15)"
|
||||||
>
|
>
|
||||||
<HStack justify="space-between" mb={4}>
|
<HStack justify="space-between" mb={4} flexWrap="wrap" gap={2}>
|
||||||
<Text fontSize="lg" fontWeight="bold" color={theme.textSecondary}>
|
<Text fontSize="md" fontWeight="bold" color={darkGoldTheme.gold}>
|
||||||
{dayStats.date}
|
{dayStats.date}
|
||||||
</Text>
|
</Text>
|
||||||
<HStack spacing={4}>
|
<HStack spacing={2} flexWrap="wrap">
|
||||||
<Badge colorScheme="blue" fontSize="md">
|
<DarkGoldBadge variant="gold">
|
||||||
交易笔数: {dayStats.count}
|
交易笔数: {dayStats.count}
|
||||||
</Badge>
|
</DarkGoldBadge>
|
||||||
<Badge colorScheme="green" fontSize="md">
|
<DarkGoldBadge variant="green">
|
||||||
成交量: {formatNumber(dayStats.total_volume)}万股
|
成交量: {formatNumber(dayStats.total_volume)}万股
|
||||||
</Badge>
|
</DarkGoldBadge>
|
||||||
<Badge colorScheme="orange" fontSize="md">
|
<DarkGoldBadge variant="orange">
|
||||||
成交额: {formatNumber(dayStats.total_amount)}万元
|
成交额: {formatNumber(dayStats.total_amount)}万元
|
||||||
</Badge>
|
</DarkGoldBadge>
|
||||||
<Badge colorScheme="purple" fontSize="md">
|
<DarkGoldBadge variant="purple">
|
||||||
均价: {dayStats.avg_price?.toFixed(2) || '-'}元
|
均价: {dayStats.avg_price?.toFixed(2) || '-'}元
|
||||||
</Badge>
|
</DarkGoldBadge>
|
||||||
</HStack>
|
</HStack>
|
||||||
</HStack>
|
</HStack>
|
||||||
|
|
||||||
{dayStats.deals && dayStats.deals.length > 0 && (
|
{dayStats.deals && dayStats.deals.length > 0 && (
|
||||||
<TableContainer>
|
<TableContainer>
|
||||||
<Table variant="simple" size="sm">
|
<Table variant="unstyled" size="sm">
|
||||||
<Thead>
|
<Thead>
|
||||||
<Tr>
|
<Tr borderBottom="1px solid" borderColor="rgba(212, 175, 55, 0.2)">
|
||||||
<Th color={theme.textSecondary}>买方营业部</Th>
|
<Th color={darkGoldTheme.textMuted} fontWeight="medium">买方营业部</Th>
|
||||||
<Th color={theme.textSecondary}>卖方营业部</Th>
|
<Th color={darkGoldTheme.textMuted} fontWeight="medium">卖方营业部</Th>
|
||||||
<Th isNumeric color={theme.textSecondary}>
|
<Th isNumeric color={darkGoldTheme.textMuted} fontWeight="medium">
|
||||||
成交价
|
成交价
|
||||||
</Th>
|
</Th>
|
||||||
<Th isNumeric color={theme.textSecondary}>
|
<Th isNumeric color={darkGoldTheme.textMuted} fontWeight="medium">
|
||||||
成交量(万股)
|
成交量(万股)
|
||||||
</Th>
|
</Th>
|
||||||
<Th isNumeric color={theme.textSecondary}>
|
<Th isNumeric color={darkGoldTheme.textMuted} fontWeight="medium">
|
||||||
成交额(万元)
|
成交额(万元)
|
||||||
</Th>
|
</Th>
|
||||||
</Tr>
|
</Tr>
|
||||||
</Thead>
|
</Thead>
|
||||||
<Tbody>
|
<Tbody>
|
||||||
{dayStats.deals.map((deal, i) => (
|
{dayStats.deals.map((deal, i) => (
|
||||||
<Tr key={i} _hover={{ bg: 'rgba(43, 108, 176, 0.05)' }}>
|
<Tr
|
||||||
|
key={i}
|
||||||
|
_hover={{ bg: 'rgba(212, 175, 55, 0.08)' }}
|
||||||
|
borderBottom="1px solid"
|
||||||
|
borderColor="rgba(212, 175, 55, 0.1)"
|
||||||
|
>
|
||||||
<Td
|
<Td
|
||||||
color={theme.textPrimary}
|
color={darkGoldTheme.textSecondary}
|
||||||
fontSize="xs"
|
fontSize="xs"
|
||||||
maxW="200px"
|
maxW="200px"
|
||||||
isTruncated
|
isTruncated
|
||||||
@@ -103,7 +147,7 @@ const BigDealPanel: React.FC<BigDealPanelProps> = ({ theme, bigDealData }) => {
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Td>
|
</Td>
|
||||||
<Td
|
<Td
|
||||||
color={theme.textPrimary}
|
color={darkGoldTheme.textSecondary}
|
||||||
fontSize="xs"
|
fontSize="xs"
|
||||||
maxW="200px"
|
maxW="200px"
|
||||||
isTruncated
|
isTruncated
|
||||||
@@ -112,13 +156,13 @@ const BigDealPanel: React.FC<BigDealPanelProps> = ({ theme, bigDealData }) => {
|
|||||||
<Text>{deal.seller_dept || '-'}</Text>
|
<Text>{deal.seller_dept || '-'}</Text>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Td>
|
</Td>
|
||||||
<Td isNumeric color={theme.textPrimary} fontWeight="bold">
|
<Td isNumeric color={darkGoldTheme.gold} fontWeight="bold">
|
||||||
{deal.price?.toFixed(2) || '-'}
|
{deal.price?.toFixed(2) || '-'}
|
||||||
</Td>
|
</Td>
|
||||||
<Td isNumeric color={theme.textPrimary}>
|
<Td isNumeric color={darkGoldTheme.textSecondary}>
|
||||||
{deal.volume?.toFixed(2) || '-'}
|
{deal.volume?.toFixed(2) || '-'}
|
||||||
</Td>
|
</Td>
|
||||||
<Td isNumeric color={theme.textSecondary} fontWeight="bold">
|
<Td isNumeric color={darkGoldTheme.orange} fontWeight="bold">
|
||||||
{deal.amount?.toFixed(2) || '-'}
|
{deal.amount?.toFixed(2) || '-'}
|
||||||
</Td>
|
</Td>
|
||||||
</Tr>
|
</Tr>
|
||||||
@@ -132,11 +176,11 @@ const BigDealPanel: React.FC<BigDealPanelProps> = ({ theme, bigDealData }) => {
|
|||||||
</VStack>
|
</VStack>
|
||||||
) : (
|
) : (
|
||||||
<Center h="200px">
|
<Center h="200px">
|
||||||
<Text color={theme.textMuted}>暂无大宗交易数据</Text>
|
<Text color={darkGoldTheme.textMuted}>暂无大宗交易数据</Text>
|
||||||
</Center>
|
</Center>
|
||||||
)}
|
)}
|
||||||
</CardBody>
|
</Box>
|
||||||
</ThemedCard>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// src/views/Company/components/MarketDataView/components/panels/PledgePanel.tsx
|
// src/views/Company/components/MarketDataView/components/panels/PledgePanel.tsx
|
||||||
// 股权质押面板 - 质押图表和表格
|
// 股权质押面板 - 黑金主题
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {
|
import {
|
||||||
@@ -12,16 +12,14 @@ import {
|
|||||||
Th,
|
Th,
|
||||||
Td,
|
Td,
|
||||||
TableContainer,
|
TableContainer,
|
||||||
CardBody,
|
|
||||||
CardHeader,
|
|
||||||
VStack,
|
VStack,
|
||||||
Heading,
|
Heading,
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import ReactECharts from 'echarts-for-react';
|
import ReactECharts from 'echarts-for-react';
|
||||||
|
|
||||||
import ThemedCard from '../ThemedCard';
|
|
||||||
import { formatNumber, formatPercent } from '../../utils/formatUtils';
|
import { formatNumber, formatPercent } from '../../utils/formatUtils';
|
||||||
import { getPledgeOption } from '../../utils/chartOptions';
|
import { getPledgeDarkGoldOption } from '../../utils/chartOptions';
|
||||||
|
import { darkGoldTheme } from '../../constants';
|
||||||
import type { Theme, PledgeData } from '../../types';
|
import type { Theme, PledgeData } from '../../types';
|
||||||
|
|
||||||
export interface PledgePanelProps {
|
export interface PledgePanelProps {
|
||||||
@@ -29,51 +27,65 @@ export interface PledgePanelProps {
|
|||||||
pledgeData: PledgeData[];
|
pledgeData: PledgeData[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const PledgePanel: React.FC<PledgePanelProps> = ({ theme, pledgeData }) => {
|
// 黑金卡片样式
|
||||||
|
const darkGoldCardStyle = {
|
||||||
|
bg: darkGoldTheme.bgCard,
|
||||||
|
border: '1px solid',
|
||||||
|
borderColor: darkGoldTheme.border,
|
||||||
|
borderRadius: 'xl',
|
||||||
|
boxShadow: '0 4px 20px rgba(0, 0, 0, 0.3)',
|
||||||
|
transition: 'all 0.3s ease',
|
||||||
|
_hover: {
|
||||||
|
borderColor: darkGoldTheme.borderHover,
|
||||||
|
boxShadow: '0 8px 30px rgba(212, 175, 55, 0.15)',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const PledgePanel: React.FC<PledgePanelProps> = ({ pledgeData }) => {
|
||||||
return (
|
return (
|
||||||
<VStack spacing={6} align="stretch">
|
<VStack spacing={6} align="stretch">
|
||||||
<ThemedCard theme={theme}>
|
{/* 图表卡片 */}
|
||||||
<CardBody>
|
<Box {...darkGoldCardStyle} p={6}>
|
||||||
{pledgeData.length > 0 && (
|
{pledgeData.length > 0 && (
|
||||||
<Box h="400px">
|
<Box h="400px">
|
||||||
<ReactECharts
|
<ReactECharts
|
||||||
option={getPledgeOption(theme, pledgeData)}
|
option={getPledgeDarkGoldOption(pledgeData)}
|
||||||
style={{ height: '100%', width: '100%' }}
|
style={{ height: '100%', width: '100%' }}
|
||||||
theme="light"
|
theme="dark"
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
</CardBody>
|
</Box>
|
||||||
</ThemedCard>
|
|
||||||
|
|
||||||
<ThemedCard theme={theme}>
|
{/* 质押明细表格 */}
|
||||||
<CardHeader>
|
<Box {...darkGoldCardStyle} overflow="hidden">
|
||||||
<Heading size="md" color={theme.textSecondary}>
|
<Box p={4} borderBottom="1px solid" borderColor={darkGoldTheme.border}>
|
||||||
|
<Heading size="md" color={darkGoldTheme.gold}>
|
||||||
质押明细
|
质押明细
|
||||||
</Heading>
|
</Heading>
|
||||||
</CardHeader>
|
</Box>
|
||||||
<CardBody>
|
<Box p={4}>
|
||||||
<TableContainer>
|
<TableContainer>
|
||||||
<Table variant="simple" size="sm">
|
<Table variant="unstyled" size="sm">
|
||||||
<Thead>
|
<Thead>
|
||||||
<Tr>
|
<Tr borderBottom="1px solid" borderColor="rgba(212, 175, 55, 0.2)">
|
||||||
<Th color={theme.textSecondary}>日期</Th>
|
<Th color={darkGoldTheme.textMuted} fontWeight="medium">日期</Th>
|
||||||
<Th isNumeric color={theme.textSecondary}>
|
<Th isNumeric color={darkGoldTheme.textMuted} fontWeight="medium">
|
||||||
无限售质押(万股)
|
无限售质押(万股)
|
||||||
</Th>
|
</Th>
|
||||||
<Th isNumeric color={theme.textSecondary}>
|
<Th isNumeric color={darkGoldTheme.textMuted} fontWeight="medium">
|
||||||
限售质押(万股)
|
限售质押(万股)
|
||||||
</Th>
|
</Th>
|
||||||
<Th isNumeric color={theme.textSecondary}>
|
<Th isNumeric color={darkGoldTheme.textMuted} fontWeight="medium">
|
||||||
质押总量(万股)
|
质押总量(万股)
|
||||||
</Th>
|
</Th>
|
||||||
<Th isNumeric color={theme.textSecondary}>
|
<Th isNumeric color={darkGoldTheme.textMuted} fontWeight="medium">
|
||||||
总股本(万股)
|
总股本(万股)
|
||||||
</Th>
|
</Th>
|
||||||
<Th isNumeric color={theme.textSecondary}>
|
<Th isNumeric color={darkGoldTheme.textMuted} fontWeight="medium">
|
||||||
质押比例
|
质押比例
|
||||||
</Th>
|
</Th>
|
||||||
<Th isNumeric color={theme.textSecondary}>
|
<Th isNumeric color={darkGoldTheme.textMuted} fontWeight="medium">
|
||||||
质押笔数
|
质押笔数
|
||||||
</Th>
|
</Th>
|
||||||
</Tr>
|
</Tr>
|
||||||
@@ -81,24 +93,29 @@ const PledgePanel: React.FC<PledgePanelProps> = ({ theme, pledgeData }) => {
|
|||||||
<Tbody>
|
<Tbody>
|
||||||
{pledgeData.length > 0 ? (
|
{pledgeData.length > 0 ? (
|
||||||
pledgeData.map((item, idx) => (
|
pledgeData.map((item, idx) => (
|
||||||
<Tr key={idx} _hover={{ bg: theme.bgDark }}>
|
<Tr
|
||||||
<Td color={theme.textPrimary}>{item.end_date}</Td>
|
key={idx}
|
||||||
<Td isNumeric color={theme.textPrimary}>
|
_hover={{ bg: 'rgba(212, 175, 55, 0.08)' }}
|
||||||
|
borderBottom="1px solid"
|
||||||
|
borderColor="rgba(212, 175, 55, 0.1)"
|
||||||
|
>
|
||||||
|
<Td color={darkGoldTheme.textSecondary}>{item.end_date}</Td>
|
||||||
|
<Td isNumeric color={darkGoldTheme.textSecondary}>
|
||||||
{formatNumber(item.unrestricted_pledge, 0)}
|
{formatNumber(item.unrestricted_pledge, 0)}
|
||||||
</Td>
|
</Td>
|
||||||
<Td isNumeric color={theme.textPrimary}>
|
<Td isNumeric color={darkGoldTheme.textSecondary}>
|
||||||
{formatNumber(item.restricted_pledge, 0)}
|
{formatNumber(item.restricted_pledge, 0)}
|
||||||
</Td>
|
</Td>
|
||||||
<Td isNumeric color={theme.textPrimary} fontWeight="bold">
|
<Td isNumeric color={darkGoldTheme.gold} fontWeight="bold">
|
||||||
{formatNumber(item.total_pledge, 0)}
|
{formatNumber(item.total_pledge, 0)}
|
||||||
</Td>
|
</Td>
|
||||||
<Td isNumeric color={theme.textPrimary}>
|
<Td isNumeric color={darkGoldTheme.textSecondary}>
|
||||||
{formatNumber(item.total_shares, 0)}
|
{formatNumber(item.total_shares, 0)}
|
||||||
</Td>
|
</Td>
|
||||||
<Td isNumeric color={theme.warning} fontWeight="bold">
|
<Td isNumeric color={darkGoldTheme.orange} fontWeight="bold">
|
||||||
{formatPercent(item.pledge_ratio)}
|
{formatPercent(item.pledge_ratio)}
|
||||||
</Td>
|
</Td>
|
||||||
<Td isNumeric color={theme.textPrimary}>
|
<Td isNumeric color={darkGoldTheme.textSecondary}>
|
||||||
{item.pledge_count}
|
{item.pledge_count}
|
||||||
</Td>
|
</Td>
|
||||||
</Tr>
|
</Tr>
|
||||||
@@ -106,7 +123,7 @@ const PledgePanel: React.FC<PledgePanelProps> = ({ theme, pledgeData }) => {
|
|||||||
) : (
|
) : (
|
||||||
<Tr>
|
<Tr>
|
||||||
<Td colSpan={7} textAlign="center" py={8}>
|
<Td colSpan={7} textAlign="center" py={8}>
|
||||||
<Text fontSize="sm" color={theme.textMuted}>
|
<Text fontSize="sm" color={darkGoldTheme.textMuted}>
|
||||||
暂无数据
|
暂无数据
|
||||||
</Text>
|
</Text>
|
||||||
</Td>
|
</Td>
|
||||||
@@ -115,8 +132,8 @@ const PledgePanel: React.FC<PledgePanelProps> = ({ theme, pledgeData }) => {
|
|||||||
</Tbody>
|
</Tbody>
|
||||||
</Table>
|
</Table>
|
||||||
</TableContainer>
|
</TableContainer>
|
||||||
</CardBody>
|
</Box>
|
||||||
</ThemedCard>
|
</Box>
|
||||||
</VStack>
|
</VStack>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import { BarChart2, Clock, TrendingUp, Calendar } from 'lucide-react';
|
|||||||
import ReactECharts from 'echarts-for-react';
|
import ReactECharts from 'echarts-for-react';
|
||||||
|
|
||||||
import { darkGoldTheme, PERIOD_OPTIONS } from '../../../constants';
|
import { darkGoldTheme, PERIOD_OPTIONS } from '../../../constants';
|
||||||
import { getKLineOption, getMinuteKLineOption } from '../../../utils/chartOptions';
|
import { getKLineDarkGoldOption, getMinuteKLineDarkGoldOption } from '../../../utils/chartOptions';
|
||||||
import type { KLineModuleProps } from '../../../types';
|
import type { KLineModuleProps } from '../../../types';
|
||||||
|
|
||||||
// 空状态组件(内联)
|
// 空状态组件(内联)
|
||||||
@@ -204,7 +204,7 @@ const KLineModule: React.FC<KLineModuleProps> = ({
|
|||||||
tradeData.length > 0 ? (
|
tradeData.length > 0 ? (
|
||||||
<Box h="600px">
|
<Box h="600px">
|
||||||
<ReactECharts
|
<ReactECharts
|
||||||
option={getKLineOption(theme, tradeData, analysisMap)}
|
option={getKLineDarkGoldOption(tradeData, analysisMap)}
|
||||||
style={{ height: '100%', width: '100%' }}
|
style={{ height: '100%', width: '100%' }}
|
||||||
theme="dark"
|
theme="dark"
|
||||||
onEvents={{ click: onChartClick }}
|
onEvents={{ click: onChartClick }}
|
||||||
@@ -233,7 +233,7 @@ const KLineModule: React.FC<KLineModuleProps> = ({
|
|||||||
) : hasMinuteData ? (
|
) : hasMinuteData ? (
|
||||||
<Box h="500px">
|
<Box h="500px">
|
||||||
<ReactECharts
|
<ReactECharts
|
||||||
option={getMinuteKLineOption(theme, minuteData)}
|
option={getMinuteKLineDarkGoldOption(minuteData)}
|
||||||
style={{ height: '100%', width: '100%' }}
|
style={{ height: '100%', width: '100%' }}
|
||||||
theme="dark"
|
theme="dark"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,22 +1,19 @@
|
|||||||
// src/views/Company/components/MarketDataView/components/panels/UnusualPanel.tsx
|
// src/views/Company/components/MarketDataView/components/panels/UnusualPanel.tsx
|
||||||
// 龙虎榜面板 - 龙虎榜数据展示
|
// 龙虎榜面板 - 黑金主题
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Text,
|
Text,
|
||||||
CardBody,
|
|
||||||
CardHeader,
|
|
||||||
Center,
|
Center,
|
||||||
Badge,
|
|
||||||
VStack,
|
VStack,
|
||||||
HStack,
|
HStack,
|
||||||
Grid,
|
Grid,
|
||||||
Heading,
|
Heading,
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
|
|
||||||
import ThemedCard from '../ThemedCard';
|
|
||||||
import { formatNumber } from '../../utils/formatUtils';
|
import { formatNumber } from '../../utils/formatUtils';
|
||||||
|
import { darkGoldTheme } from '../../constants';
|
||||||
import type { Theme, UnusualData } from '../../types';
|
import type { Theme, UnusualData } from '../../types';
|
||||||
|
|
||||||
export interface UnusualPanelProps {
|
export interface UnusualPanelProps {
|
||||||
@@ -24,49 +21,87 @@ export interface UnusualPanelProps {
|
|||||||
unusualData: UnusualData;
|
unusualData: UnusualData;
|
||||||
}
|
}
|
||||||
|
|
||||||
const UnusualPanel: React.FC<UnusualPanelProps> = ({ theme, unusualData }) => {
|
// 黑金卡片样式
|
||||||
|
const darkGoldCardStyle = {
|
||||||
|
bg: darkGoldTheme.bgCard,
|
||||||
|
border: '1px solid',
|
||||||
|
borderColor: darkGoldTheme.border,
|
||||||
|
borderRadius: 'xl',
|
||||||
|
boxShadow: '0 4px 20px rgba(0, 0, 0, 0.3)',
|
||||||
|
transition: 'all 0.3s ease',
|
||||||
|
_hover: {
|
||||||
|
borderColor: darkGoldTheme.borderHover,
|
||||||
|
boxShadow: '0 8px 30px rgba(212, 175, 55, 0.15)',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// 黑金徽章样式
|
||||||
|
const DarkGoldBadge: React.FC<{ children: React.ReactNode; variant?: 'red' | 'green' | 'gold' }> = ({
|
||||||
|
children,
|
||||||
|
variant = 'gold',
|
||||||
|
}) => {
|
||||||
|
const colors = {
|
||||||
|
red: { bg: 'rgba(255, 68, 68, 0.15)', color: darkGoldTheme.red },
|
||||||
|
green: { bg: 'rgba(0, 200, 81, 0.15)', color: darkGoldTheme.green },
|
||||||
|
gold: { bg: 'rgba(212, 175, 55, 0.15)', color: darkGoldTheme.gold },
|
||||||
|
};
|
||||||
|
const style = colors[variant];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ThemedCard theme={theme}>
|
<Box
|
||||||
<CardHeader>
|
px={2}
|
||||||
<Heading size="md" color={theme.textSecondary}>
|
py={1}
|
||||||
|
bg={style.bg}
|
||||||
|
color={style.color}
|
||||||
|
borderRadius="md"
|
||||||
|
fontSize="xs"
|
||||||
|
fontWeight="medium"
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const UnusualPanel: React.FC<UnusualPanelProps> = ({ unusualData }) => {
|
||||||
|
return (
|
||||||
|
<Box {...darkGoldCardStyle} overflow="hidden">
|
||||||
|
<Box p={4} borderBottom="1px solid" borderColor={darkGoldTheme.border}>
|
||||||
|
<Heading size="md" color={darkGoldTheme.gold}>
|
||||||
龙虎榜数据
|
龙虎榜数据
|
||||||
</Heading>
|
</Heading>
|
||||||
</CardHeader>
|
</Box>
|
||||||
<CardBody>
|
<Box p={4}>
|
||||||
{unusualData?.grouped_data && unusualData.grouped_data.length > 0 ? (
|
{unusualData?.grouped_data && unusualData.grouped_data.length > 0 ? (
|
||||||
<VStack spacing={6} align="stretch">
|
<VStack spacing={4} align="stretch">
|
||||||
{unusualData.grouped_data.map((dayData, idx) => (
|
{unusualData.grouped_data.map((dayData, idx) => (
|
||||||
<Box
|
<Box
|
||||||
key={idx}
|
key={idx}
|
||||||
p={4}
|
p={4}
|
||||||
bg={theme.bgDark}
|
bg="rgba(212, 175, 55, 0.05)"
|
||||||
borderRadius="lg"
|
borderRadius="lg"
|
||||||
border="1px solid"
|
border="1px solid"
|
||||||
borderColor={theme.border}
|
borderColor="rgba(212, 175, 55, 0.15)"
|
||||||
>
|
>
|
||||||
<HStack justify="space-between" mb={4}>
|
<HStack justify="space-between" mb={4} flexWrap="wrap" gap={2}>
|
||||||
<Text fontSize="lg" fontWeight="bold" color={theme.textSecondary}>
|
<Text fontSize="md" fontWeight="bold" color={darkGoldTheme.gold}>
|
||||||
{dayData.date}
|
{dayData.date}
|
||||||
</Text>
|
</Text>
|
||||||
<HStack spacing={4}>
|
<HStack spacing={2} flexWrap="wrap">
|
||||||
<Badge colorScheme="red" fontSize="md">
|
<DarkGoldBadge variant="red">
|
||||||
买入: {formatNumber(dayData.total_buy)}
|
买入: {formatNumber(dayData.total_buy)}
|
||||||
</Badge>
|
</DarkGoldBadge>
|
||||||
<Badge colorScheme="green" fontSize="md">
|
<DarkGoldBadge variant="green">
|
||||||
卖出: {formatNumber(dayData.total_sell)}
|
卖出: {formatNumber(dayData.total_sell)}
|
||||||
</Badge>
|
</DarkGoldBadge>
|
||||||
<Badge
|
<DarkGoldBadge variant={dayData.net_amount > 0 ? 'red' : 'green'}>
|
||||||
colorScheme={dayData.net_amount > 0 ? 'red' : 'green'}
|
|
||||||
fontSize="md"
|
|
||||||
>
|
|
||||||
净额: {formatNumber(dayData.net_amount)}
|
净额: {formatNumber(dayData.net_amount)}
|
||||||
</Badge>
|
</DarkGoldBadge>
|
||||||
</HStack>
|
</HStack>
|
||||||
</HStack>
|
</HStack>
|
||||||
|
|
||||||
<Grid templateColumns="repeat(2, 1fr)" gap={4}>
|
<Grid templateColumns="repeat(2, 1fr)" gap={4}>
|
||||||
<Box>
|
<Box>
|
||||||
<Text fontWeight="bold" color={theme.success} mb={2}>
|
<Text fontWeight="bold" color={darkGoldTheme.red} mb={2} fontSize="sm">
|
||||||
买入前五
|
买入前五
|
||||||
</Text>
|
</Text>
|
||||||
<VStack spacing={1} align="stretch">
|
<VStack spacing={1} align="stretch">
|
||||||
@@ -76,24 +111,31 @@ const UnusualPanel: React.FC<UnusualPanelProps> = ({ theme, unusualData }) => {
|
|||||||
key={i}
|
key={i}
|
||||||
justify="space-between"
|
justify="space-between"
|
||||||
p={2}
|
p={2}
|
||||||
bg="rgba(255, 68, 68, 0.05)"
|
bg="rgba(255, 68, 68, 0.08)"
|
||||||
borderRadius="md"
|
borderRadius="md"
|
||||||
|
border="1px solid"
|
||||||
|
borderColor="rgba(255, 68, 68, 0.15)"
|
||||||
|
transition="all 0.2s"
|
||||||
|
_hover={{
|
||||||
|
bg: 'rgba(255, 68, 68, 0.12)',
|
||||||
|
borderColor: 'rgba(255, 68, 68, 0.3)',
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Text
|
<Text
|
||||||
fontSize="sm"
|
fontSize="xs"
|
||||||
color={theme.textPrimary}
|
color={darkGoldTheme.textSecondary}
|
||||||
isTruncated
|
isTruncated
|
||||||
maxW="70%"
|
maxW="70%"
|
||||||
>
|
>
|
||||||
{buyer.dept_name}
|
{buyer.dept_name}
|
||||||
</Text>
|
</Text>
|
||||||
<Text fontSize="sm" color={theme.success} fontWeight="bold">
|
<Text fontSize="xs" color={darkGoldTheme.red} fontWeight="bold">
|
||||||
{formatNumber(buyer.buy_amount)}
|
{formatNumber(buyer.buy_amount)}
|
||||||
</Text>
|
</Text>
|
||||||
</HStack>
|
</HStack>
|
||||||
))
|
))
|
||||||
) : (
|
) : (
|
||||||
<Text fontSize="sm" color={theme.textMuted}>
|
<Text fontSize="xs" color={darkGoldTheme.textMuted}>
|
||||||
暂无数据
|
暂无数据
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
@@ -101,7 +143,7 @@ const UnusualPanel: React.FC<UnusualPanelProps> = ({ theme, unusualData }) => {
|
|||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Text fontWeight="bold" color={theme.danger} mb={2}>
|
<Text fontWeight="bold" color={darkGoldTheme.green} mb={2} fontSize="sm">
|
||||||
卖出前五
|
卖出前五
|
||||||
</Text>
|
</Text>
|
||||||
<VStack spacing={1} align="stretch">
|
<VStack spacing={1} align="stretch">
|
||||||
@@ -111,24 +153,31 @@ const UnusualPanel: React.FC<UnusualPanelProps> = ({ theme, unusualData }) => {
|
|||||||
key={i}
|
key={i}
|
||||||
justify="space-between"
|
justify="space-between"
|
||||||
p={2}
|
p={2}
|
||||||
bg="rgba(0, 200, 81, 0.05)"
|
bg="rgba(0, 200, 81, 0.08)"
|
||||||
borderRadius="md"
|
borderRadius="md"
|
||||||
|
border="1px solid"
|
||||||
|
borderColor="rgba(0, 200, 81, 0.15)"
|
||||||
|
transition="all 0.2s"
|
||||||
|
_hover={{
|
||||||
|
bg: 'rgba(0, 200, 81, 0.12)',
|
||||||
|
borderColor: 'rgba(0, 200, 81, 0.3)',
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Text
|
<Text
|
||||||
fontSize="sm"
|
fontSize="xs"
|
||||||
color={theme.textPrimary}
|
color={darkGoldTheme.textSecondary}
|
||||||
isTruncated
|
isTruncated
|
||||||
maxW="70%"
|
maxW="70%"
|
||||||
>
|
>
|
||||||
{seller.dept_name}
|
{seller.dept_name}
|
||||||
</Text>
|
</Text>
|
||||||
<Text fontSize="sm" color={theme.danger} fontWeight="bold">
|
<Text fontSize="xs" color={darkGoldTheme.green} fontWeight="bold">
|
||||||
{formatNumber(seller.sell_amount)}
|
{formatNumber(seller.sell_amount)}
|
||||||
</Text>
|
</Text>
|
||||||
</HStack>
|
</HStack>
|
||||||
))
|
))
|
||||||
) : (
|
) : (
|
||||||
<Text fontSize="sm" color={theme.textMuted}>
|
<Text fontSize="xs" color={darkGoldTheme.textMuted}>
|
||||||
暂无数据
|
暂无数据
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
@@ -137,14 +186,22 @@ const UnusualPanel: React.FC<UnusualPanelProps> = ({ theme, unusualData }) => {
|
|||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
{/* 信息类型标签 */}
|
{/* 信息类型标签 */}
|
||||||
<HStack mt={3} spacing={2}>
|
<HStack mt={3} spacing={2} flexWrap="wrap">
|
||||||
<Text fontSize="sm" color={theme.textMuted}>
|
<Text fontSize="xs" color={darkGoldTheme.textMuted}>
|
||||||
类型:
|
类型:
|
||||||
</Text>
|
</Text>
|
||||||
{dayData.info_types?.map((type, i) => (
|
{dayData.info_types?.map((type, i) => (
|
||||||
<Badge key={i} colorScheme="blue" fontSize="xs">
|
<Box
|
||||||
|
key={i}
|
||||||
|
px={2}
|
||||||
|
py={0.5}
|
||||||
|
bg="rgba(212, 175, 55, 0.1)"
|
||||||
|
color={darkGoldTheme.gold}
|
||||||
|
borderRadius="sm"
|
||||||
|
fontSize="xs"
|
||||||
|
>
|
||||||
{type}
|
{type}
|
||||||
</Badge>
|
</Box>
|
||||||
))}
|
))}
|
||||||
</HStack>
|
</HStack>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -152,11 +209,11 @@ const UnusualPanel: React.FC<UnusualPanelProps> = ({ theme, unusualData }) => {
|
|||||||
</VStack>
|
</VStack>
|
||||||
) : (
|
) : (
|
||||||
<Center h="200px">
|
<Center h="200px">
|
||||||
<Text color={theme.textMuted}>暂无龙虎榜数据</Text>
|
<Text color={darkGoldTheme.textMuted}>暂无龙虎榜数据</Text>
|
||||||
</Center>
|
</Center>
|
||||||
)}
|
)}
|
||||||
</CardBody>
|
</Box>
|
||||||
</ThemedCard>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user