style(Panels): 应用黑金主题样式

This commit is contained in:
zdl
2025-12-16 15:24:13 +08:00
parent 59f4b1cdb9
commit 391955f88c
4 changed files with 251 additions and 133 deletions

View File

@@ -1,5 +1,5 @@
// src/views/Company/components/MarketDataView/components/panels/BigDealPanel.tsx
// 大宗交易面板 - 大宗交易记录表格
// 大宗交易面板 - 黑金主题
import React from 'react';
import {
@@ -12,18 +12,15 @@ import {
Th,
Td,
TableContainer,
CardBody,
CardHeader,
Center,
Badge,
VStack,
HStack,
Tooltip,
Heading,
} from '@chakra-ui/react';
import ThemedCard from '../ThemedCard';
import { formatNumber } from '../../utils/formatUtils';
import { darkGoldTheme } from '../../constants';
import type { Theme, BigDealData } from '../../types';
export interface BigDealPanelProps {
@@ -31,69 +28,116 @@ export interface BigDealPanelProps {
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 (
<ThemedCard theme={theme}>
<CardHeader>
<Heading size="md" color={theme.textSecondary}>
<Box
px={2}
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>
</CardHeader>
<CardBody>
</Box>
<Box p={4}>
{bigDealData?.daily_stats && bigDealData.daily_stats.length > 0 ? (
<VStack spacing={6} align="stretch">
<VStack spacing={4} align="stretch">
{bigDealData.daily_stats.map((dayStats, idx) => (
<Box
key={idx}
p={4}
bg={theme.bgDark}
bg="rgba(212, 175, 55, 0.05)"
borderRadius="lg"
border="1px solid"
borderColor={theme.border}
borderColor="rgba(212, 175, 55, 0.15)"
>
<HStack justify="space-between" mb={4}>
<Text fontSize="lg" fontWeight="bold" color={theme.textSecondary}>
<HStack justify="space-between" mb={4} flexWrap="wrap" gap={2}>
<Text fontSize="md" fontWeight="bold" color={darkGoldTheme.gold}>
{dayStats.date}
</Text>
<HStack spacing={4}>
<Badge colorScheme="blue" fontSize="md">
<HStack spacing={2} flexWrap="wrap">
<DarkGoldBadge variant="gold">
: {dayStats.count}
</Badge>
<Badge colorScheme="green" fontSize="md">
</DarkGoldBadge>
<DarkGoldBadge variant="green">
: {formatNumber(dayStats.total_volume)}
</Badge>
<Badge colorScheme="orange" fontSize="md">
</DarkGoldBadge>
<DarkGoldBadge variant="orange">
: {formatNumber(dayStats.total_amount)}
</Badge>
<Badge colorScheme="purple" fontSize="md">
</DarkGoldBadge>
<DarkGoldBadge variant="purple">
: {dayStats.avg_price?.toFixed(2) || '-'}
</Badge>
</DarkGoldBadge>
</HStack>
</HStack>
{dayStats.deals && dayStats.deals.length > 0 && (
<TableContainer>
<Table variant="simple" size="sm">
<Table variant="unstyled" size="sm">
<Thead>
<Tr>
<Th color={theme.textSecondary}></Th>
<Th color={theme.textSecondary}></Th>
<Th isNumeric color={theme.textSecondary}>
<Tr borderBottom="1px solid" borderColor="rgba(212, 175, 55, 0.2)">
<Th color={darkGoldTheme.textMuted} fontWeight="medium"></Th>
<Th color={darkGoldTheme.textMuted} fontWeight="medium"></Th>
<Th isNumeric color={darkGoldTheme.textMuted} fontWeight="medium">
</Th>
<Th isNumeric color={theme.textSecondary}>
<Th isNumeric color={darkGoldTheme.textMuted} fontWeight="medium">
()
</Th>
<Th isNumeric color={theme.textSecondary}>
<Th isNumeric color={darkGoldTheme.textMuted} fontWeight="medium">
()
</Th>
</Tr>
</Thead>
<Tbody>
{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
color={theme.textPrimary}
color={darkGoldTheme.textSecondary}
fontSize="xs"
maxW="200px"
isTruncated
@@ -103,7 +147,7 @@ const BigDealPanel: React.FC<BigDealPanelProps> = ({ theme, bigDealData }) => {
</Tooltip>
</Td>
<Td
color={theme.textPrimary}
color={darkGoldTheme.textSecondary}
fontSize="xs"
maxW="200px"
isTruncated
@@ -112,13 +156,13 @@ const BigDealPanel: React.FC<BigDealPanelProps> = ({ theme, bigDealData }) => {
<Text>{deal.seller_dept || '-'}</Text>
</Tooltip>
</Td>
<Td isNumeric color={theme.textPrimary} fontWeight="bold">
<Td isNumeric color={darkGoldTheme.gold} fontWeight="bold">
{deal.price?.toFixed(2) || '-'}
</Td>
<Td isNumeric color={theme.textPrimary}>
<Td isNumeric color={darkGoldTheme.textSecondary}>
{deal.volume?.toFixed(2) || '-'}
</Td>
<Td isNumeric color={theme.textSecondary} fontWeight="bold">
<Td isNumeric color={darkGoldTheme.orange} fontWeight="bold">
{deal.amount?.toFixed(2) || '-'}
</Td>
</Tr>
@@ -132,11 +176,11 @@ const BigDealPanel: React.FC<BigDealPanelProps> = ({ theme, bigDealData }) => {
</VStack>
) : (
<Center h="200px">
<Text color={theme.textMuted}></Text>
<Text color={darkGoldTheme.textMuted}></Text>
</Center>
)}
</CardBody>
</ThemedCard>
</Box>
</Box>
);
};

View File

@@ -1,5 +1,5 @@
// src/views/Company/components/MarketDataView/components/panels/PledgePanel.tsx
// 股权质押面板 - 质押图表和表格
// 股权质押面板 - 黑金主题
import React from 'react';
import {
@@ -12,16 +12,14 @@ import {
Th,
Td,
TableContainer,
CardBody,
CardHeader,
VStack,
Heading,
} from '@chakra-ui/react';
import ReactECharts from 'echarts-for-react';
import ThemedCard from '../ThemedCard';
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';
export interface PledgePanelProps {
@@ -29,51 +27,65 @@ export interface PledgePanelProps {
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 (
<VStack spacing={6} align="stretch">
<ThemedCard theme={theme}>
<CardBody>
{/* 图表卡片 */}
<Box {...darkGoldCardStyle} p={6}>
{pledgeData.length > 0 && (
<Box h="400px">
<ReactECharts
option={getPledgeOption(theme, pledgeData)}
option={getPledgeDarkGoldOption(pledgeData)}
style={{ height: '100%', width: '100%' }}
theme="light"
theme="dark"
/>
</Box>
)}
</CardBody>
</ThemedCard>
</Box>
<ThemedCard theme={theme}>
<CardHeader>
<Heading size="md" color={theme.textSecondary}>
{/* 质押明细表格 */}
<Box {...darkGoldCardStyle} overflow="hidden">
<Box p={4} borderBottom="1px solid" borderColor={darkGoldTheme.border}>
<Heading size="md" color={darkGoldTheme.gold}>
</Heading>
</CardHeader>
<CardBody>
</Box>
<Box p={4}>
<TableContainer>
<Table variant="simple" size="sm">
<Table variant="unstyled" size="sm">
<Thead>
<Tr>
<Th color={theme.textSecondary}></Th>
<Th isNumeric color={theme.textSecondary}>
<Tr borderBottom="1px solid" borderColor="rgba(212, 175, 55, 0.2)">
<Th color={darkGoldTheme.textMuted} fontWeight="medium"></Th>
<Th isNumeric color={darkGoldTheme.textMuted} fontWeight="medium">
()
</Th>
<Th isNumeric color={theme.textSecondary}>
<Th isNumeric color={darkGoldTheme.textMuted} fontWeight="medium">
()
</Th>
<Th isNumeric color={theme.textSecondary}>
<Th isNumeric color={darkGoldTheme.textMuted} fontWeight="medium">
()
</Th>
<Th isNumeric color={theme.textSecondary}>
<Th isNumeric color={darkGoldTheme.textMuted} fontWeight="medium">
()
</Th>
<Th isNumeric color={theme.textSecondary}>
<Th isNumeric color={darkGoldTheme.textMuted} fontWeight="medium">
</Th>
<Th isNumeric color={theme.textSecondary}>
<Th isNumeric color={darkGoldTheme.textMuted} fontWeight="medium">
</Th>
</Tr>
@@ -81,24 +93,29 @@ const PledgePanel: React.FC<PledgePanelProps> = ({ theme, pledgeData }) => {
<Tbody>
{pledgeData.length > 0 ? (
pledgeData.map((item, idx) => (
<Tr key={idx} _hover={{ bg: theme.bgDark }}>
<Td color={theme.textPrimary}>{item.end_date}</Td>
<Td isNumeric color={theme.textPrimary}>
<Tr
key={idx}
_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)}
</Td>
<Td isNumeric color={theme.textPrimary}>
<Td isNumeric color={darkGoldTheme.textSecondary}>
{formatNumber(item.restricted_pledge, 0)}
</Td>
<Td isNumeric color={theme.textPrimary} fontWeight="bold">
<Td isNumeric color={darkGoldTheme.gold} fontWeight="bold">
{formatNumber(item.total_pledge, 0)}
</Td>
<Td isNumeric color={theme.textPrimary}>
<Td isNumeric color={darkGoldTheme.textSecondary}>
{formatNumber(item.total_shares, 0)}
</Td>
<Td isNumeric color={theme.warning} fontWeight="bold">
<Td isNumeric color={darkGoldTheme.orange} fontWeight="bold">
{formatPercent(item.pledge_ratio)}
</Td>
<Td isNumeric color={theme.textPrimary}>
<Td isNumeric color={darkGoldTheme.textSecondary}>
{item.pledge_count}
</Td>
</Tr>
@@ -106,7 +123,7 @@ const PledgePanel: React.FC<PledgePanelProps> = ({ theme, pledgeData }) => {
) : (
<Tr>
<Td colSpan={7} textAlign="center" py={8}>
<Text fontSize="sm" color={theme.textMuted}>
<Text fontSize="sm" color={darkGoldTheme.textMuted}>
</Text>
</Td>
@@ -115,8 +132,8 @@ const PledgePanel: React.FC<PledgePanelProps> = ({ theme, pledgeData }) => {
</Tbody>
</Table>
</TableContainer>
</CardBody>
</ThemedCard>
</Box>
</Box>
</VStack>
);
};

View File

@@ -20,7 +20,7 @@ import { BarChart2, Clock, TrendingUp, Calendar } from 'lucide-react';
import ReactECharts from 'echarts-for-react';
import { darkGoldTheme, PERIOD_OPTIONS } from '../../../constants';
import { getKLineOption, getMinuteKLineOption } from '../../../utils/chartOptions';
import { getKLineDarkGoldOption, getMinuteKLineDarkGoldOption } from '../../../utils/chartOptions';
import type { KLineModuleProps } from '../../../types';
// 空状态组件(内联)
@@ -204,7 +204,7 @@ const KLineModule: React.FC<KLineModuleProps> = ({
tradeData.length > 0 ? (
<Box h="600px">
<ReactECharts
option={getKLineOption(theme, tradeData, analysisMap)}
option={getKLineDarkGoldOption(tradeData, analysisMap)}
style={{ height: '100%', width: '100%' }}
theme="dark"
onEvents={{ click: onChartClick }}
@@ -233,7 +233,7 @@ const KLineModule: React.FC<KLineModuleProps> = ({
) : hasMinuteData ? (
<Box h="500px">
<ReactECharts
option={getMinuteKLineOption(theme, minuteData)}
option={getMinuteKLineDarkGoldOption(minuteData)}
style={{ height: '100%', width: '100%' }}
theme="dark"
/>

View File

@@ -1,22 +1,19 @@
// src/views/Company/components/MarketDataView/components/panels/UnusualPanel.tsx
// 龙虎榜面板 - 龙虎榜数据展示
// 龙虎榜面板 - 黑金主题
import React from 'react';
import {
Box,
Text,
CardBody,
CardHeader,
Center,
Badge,
VStack,
HStack,
Grid,
Heading,
} from '@chakra-ui/react';
import ThemedCard from '../ThemedCard';
import { formatNumber } from '../../utils/formatUtils';
import { darkGoldTheme } from '../../constants';
import type { Theme, UnusualData } from '../../types';
export interface UnusualPanelProps {
@@ -24,49 +21,87 @@ export interface UnusualPanelProps {
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 (
<ThemedCard theme={theme}>
<CardHeader>
<Heading size="md" color={theme.textSecondary}>
<Box
px={2}
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>
</CardHeader>
<CardBody>
</Box>
<Box p={4}>
{unusualData?.grouped_data && unusualData.grouped_data.length > 0 ? (
<VStack spacing={6} align="stretch">
<VStack spacing={4} align="stretch">
{unusualData.grouped_data.map((dayData, idx) => (
<Box
key={idx}
p={4}
bg={theme.bgDark}
bg="rgba(212, 175, 55, 0.05)"
borderRadius="lg"
border="1px solid"
borderColor={theme.border}
borderColor="rgba(212, 175, 55, 0.15)"
>
<HStack justify="space-between" mb={4}>
<Text fontSize="lg" fontWeight="bold" color={theme.textSecondary}>
<HStack justify="space-between" mb={4} flexWrap="wrap" gap={2}>
<Text fontSize="md" fontWeight="bold" color={darkGoldTheme.gold}>
{dayData.date}
</Text>
<HStack spacing={4}>
<Badge colorScheme="red" fontSize="md">
<HStack spacing={2} flexWrap="wrap">
<DarkGoldBadge variant="red">
: {formatNumber(dayData.total_buy)}
</Badge>
<Badge colorScheme="green" fontSize="md">
</DarkGoldBadge>
<DarkGoldBadge variant="green">
: {formatNumber(dayData.total_sell)}
</Badge>
<Badge
colorScheme={dayData.net_amount > 0 ? 'red' : 'green'}
fontSize="md"
>
</DarkGoldBadge>
<DarkGoldBadge variant={dayData.net_amount > 0 ? 'red' : 'green'}>
: {formatNumber(dayData.net_amount)}
</Badge>
</DarkGoldBadge>
</HStack>
</HStack>
<Grid templateColumns="repeat(2, 1fr)" gap={4}>
<Box>
<Text fontWeight="bold" color={theme.success} mb={2}>
<Text fontWeight="bold" color={darkGoldTheme.red} mb={2} fontSize="sm">
</Text>
<VStack spacing={1} align="stretch">
@@ -76,24 +111,31 @@ const UnusualPanel: React.FC<UnusualPanelProps> = ({ theme, unusualData }) => {
key={i}
justify="space-between"
p={2}
bg="rgba(255, 68, 68, 0.05)"
bg="rgba(255, 68, 68, 0.08)"
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
fontSize="sm"
color={theme.textPrimary}
fontSize="xs"
color={darkGoldTheme.textSecondary}
isTruncated
maxW="70%"
>
{buyer.dept_name}
</Text>
<Text fontSize="sm" color={theme.success} fontWeight="bold">
<Text fontSize="xs" color={darkGoldTheme.red} fontWeight="bold">
{formatNumber(buyer.buy_amount)}
</Text>
</HStack>
))
) : (
<Text fontSize="sm" color={theme.textMuted}>
<Text fontSize="xs" color={darkGoldTheme.textMuted}>
</Text>
)}
@@ -101,7 +143,7 @@ const UnusualPanel: React.FC<UnusualPanelProps> = ({ theme, unusualData }) => {
</Box>
<Box>
<Text fontWeight="bold" color={theme.danger} mb={2}>
<Text fontWeight="bold" color={darkGoldTheme.green} mb={2} fontSize="sm">
</Text>
<VStack spacing={1} align="stretch">
@@ -111,24 +153,31 @@ const UnusualPanel: React.FC<UnusualPanelProps> = ({ theme, unusualData }) => {
key={i}
justify="space-between"
p={2}
bg="rgba(0, 200, 81, 0.05)"
bg="rgba(0, 200, 81, 0.08)"
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
fontSize="sm"
color={theme.textPrimary}
fontSize="xs"
color={darkGoldTheme.textSecondary}
isTruncated
maxW="70%"
>
{seller.dept_name}
</Text>
<Text fontSize="sm" color={theme.danger} fontWeight="bold">
<Text fontSize="xs" color={darkGoldTheme.green} fontWeight="bold">
{formatNumber(seller.sell_amount)}
</Text>
</HStack>
))
) : (
<Text fontSize="sm" color={theme.textMuted}>
<Text fontSize="xs" color={darkGoldTheme.textMuted}>
</Text>
)}
@@ -137,14 +186,22 @@ const UnusualPanel: React.FC<UnusualPanelProps> = ({ theme, unusualData }) => {
</Grid>
{/* 信息类型标签 */}
<HStack mt={3} spacing={2}>
<Text fontSize="sm" color={theme.textMuted}>
<HStack mt={3} spacing={2} flexWrap="wrap">
<Text fontSize="xs" color={darkGoldTheme.textMuted}>
:
</Text>
{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}
</Badge>
</Box>
))}
</HStack>
</Box>
@@ -152,11 +209,11 @@ const UnusualPanel: React.FC<UnusualPanelProps> = ({ theme, unusualData }) => {
</VStack>
) : (
<Center h="200px">
<Text color={theme.textMuted}></Text>
<Text color={darkGoldTheme.textMuted}></Text>
</Center>
)}
</CardBody>
</ThemedCard>
</Box>
</Box>
);
};