pref: FundingPanel 黑金主题改造 融资融券面板

This commit is contained in:
zdl
2025-12-16 15:11:52 +08:00
parent 1022fa4077
commit 03bc2d681b
2 changed files with 230 additions and 41 deletions

View File

@@ -1,12 +1,10 @@
// src/views/Company/components/MarketDataView/components/panels/FundingPanel.tsx // src/views/Company/components/MarketDataView/components/panels/FundingPanel.tsx
// 融资融券面板 - 融资融券数据图表和卡片 // 融资融券面板 - 黑金主题
import React from 'react'; import React from 'react';
import { import {
Box, Box,
Text, Text,
CardBody,
CardHeader,
VStack, VStack,
HStack, HStack,
Grid, Grid,
@@ -14,9 +12,9 @@ import {
} 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 } from '../../utils/formatUtils'; import { formatNumber } from '../../utils/formatUtils';
import { getFundingOption } from '../../utils/chartOptions'; import { getFundingDarkGoldOption } from '../../utils/chartOptions';
import { darkGoldTheme } from '../../constants';
import type { Theme, FundingDayData } from '../../types'; import type { Theme, FundingDayData } from '../../types';
export interface FundingPanelProps { export interface FundingPanelProps {
@@ -24,45 +22,73 @@ export interface FundingPanelProps {
fundingData: FundingDayData[]; fundingData: FundingDayData[];
} }
const FundingPanel: React.FC<FundingPanelProps> = ({ theme, fundingData }) => { // 黑金卡片样式
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)',
transform: 'translateY(-2px)',
},
};
const FundingPanel: React.FC<FundingPanelProps> = ({ fundingData }) => {
return ( return (
<VStack spacing={6} align="stretch"> <VStack spacing={6} align="stretch">
<ThemedCard theme={theme}> {/* 图表卡片 */}
<CardBody> <Box {...darkGoldCardStyle} p={6}>
{fundingData.length > 0 && ( {fundingData.length > 0 && (
<Box h="400px"> <Box h="400px">
<ReactECharts <ReactECharts
option={getFundingOption(theme, fundingData)} option={getFundingDarkGoldOption(fundingData)}
style={{ height: '100%', width: '100%' }} style={{ height: '100%', width: '100%' }}
theme="light" theme="dark"
/> />
</Box> </Box>
)} )}
</CardBody> </Box>
</ThemedCard>
<Grid templateColumns="repeat(2, 1fr)" gap={6}> <Grid templateColumns="repeat(2, 1fr)" gap={6}>
{/* 融资数据 */} {/* 融资数据 */}
<ThemedCard theme={theme}> <Box {...darkGoldCardStyle} overflow="hidden">
<CardHeader> <Box p={4} borderBottom="1px solid" borderColor={darkGoldTheme.border}>
<Heading size="md" color={theme.success}> <Heading size="md" color={darkGoldTheme.gold}>
</Heading> </Heading>
</CardHeader> </Box>
<CardBody> <Box p={4}>
<VStack spacing={3} align="stretch"> <VStack spacing={3} align="stretch">
{fundingData {fundingData
.slice(-5) .slice(-5)
.reverse() .reverse()
.map((item, idx) => ( .map((item, idx) => (
<Box key={idx} p={3} bg="rgba(255, 68, 68, 0.05)" borderRadius="md"> <Box
key={idx}
p={3}
bg="rgba(212, 175, 55, 0.08)"
borderRadius="md"
border="1px solid"
borderColor="rgba(212, 175, 55, 0.15)"
transition="all 0.2s"
_hover={{
bg: 'rgba(212, 175, 55, 0.12)',
borderColor: 'rgba(212, 175, 55, 0.3)',
}}
>
<HStack justify="space-between"> <HStack justify="space-between">
<Text color={theme.textMuted}>{item.date}</Text> <Text color={darkGoldTheme.textMuted} fontSize="sm">
{item.date}
</Text>
<VStack align="end" spacing={0}> <VStack align="end" spacing={0}>
<Text color={theme.textPrimary} fontWeight="bold"> <Text color={darkGoldTheme.gold} fontWeight="bold">
{formatNumber(item.financing.balance)} {formatNumber(item.financing.balance)}
</Text> </Text>
<Text fontSize="xs" color={theme.textMuted}> <Text fontSize="xs" color={darkGoldTheme.textMuted}>
{formatNumber(item.financing.buy)} / {formatNumber(item.financing.buy)} /
{formatNumber(item.financing.repay)} {formatNumber(item.financing.repay)}
</Text> </Text>
@@ -71,30 +97,44 @@ const FundingPanel: React.FC<FundingPanelProps> = ({ theme, fundingData }) => {
</Box> </Box>
))} ))}
</VStack> </VStack>
</CardBody> </Box>
</ThemedCard> </Box>
{/* 融券数据 */} {/* 融券数据 */}
<ThemedCard theme={theme}> <Box {...darkGoldCardStyle} overflow="hidden">
<CardHeader> <Box p={4} borderBottom="1px solid" borderColor={darkGoldTheme.border}>
<Heading size="md" color={theme.danger}> <Heading size="md" color={darkGoldTheme.orange}>
</Heading> </Heading>
</CardHeader> </Box>
<CardBody> <Box p={4}>
<VStack spacing={3} align="stretch"> <VStack spacing={3} align="stretch">
{fundingData {fundingData
.slice(-5) .slice(-5)
.reverse() .reverse()
.map((item, idx) => ( .map((item, idx) => (
<Box key={idx} p={3} bg="rgba(0, 200, 81, 0.05)" borderRadius="md"> <Box
key={idx}
p={3}
bg="rgba(255, 149, 0, 0.08)"
borderRadius="md"
border="1px solid"
borderColor="rgba(255, 149, 0, 0.15)"
transition="all 0.2s"
_hover={{
bg: 'rgba(255, 149, 0, 0.12)',
borderColor: 'rgba(255, 149, 0, 0.3)',
}}
>
<HStack justify="space-between"> <HStack justify="space-between">
<Text color={theme.textMuted}>{item.date}</Text> <Text color={darkGoldTheme.textMuted} fontSize="sm">
{item.date}
</Text>
<VStack align="end" spacing={0}> <VStack align="end" spacing={0}>
<Text color={theme.textPrimary} fontWeight="bold"> <Text color={darkGoldTheme.orange} fontWeight="bold">
{formatNumber(item.securities.balance)} {formatNumber(item.securities.balance)}
</Text> </Text>
<Text fontSize="xs" color={theme.textMuted}> <Text fontSize="xs" color={darkGoldTheme.textMuted}>
{formatNumber(item.securities.sell)} / {formatNumber(item.securities.sell)} /
{formatNumber(item.securities.repay)} {formatNumber(item.securities.repay)}
</Text> </Text>
@@ -103,8 +143,8 @@ const FundingPanel: React.FC<FundingPanelProps> = ({ theme, fundingData }) => {
</Box> </Box>
))} ))}
</VStack> </VStack>
</CardBody> </Box>
</ThemedCard> </Box>
</Grid> </Grid>
</VStack> </VStack>
); );

View File

@@ -575,6 +575,154 @@ export const getFundingOption = (theme: Theme, fundingData: FundingDayData[]): E
}; };
}; };
/**
* 生成融资融券图表配置 - 黑金主题
*/
export const getFundingDarkGoldOption = (fundingData: FundingDayData[]): EChartsOption => {
if (!fundingData || fundingData.length === 0) return {};
const dates = fundingData.map((item) => item.date.substring(5, 10));
const financing = fundingData.map((item) => item.financing.balance / 100000000);
const securities = fundingData.map((item) => item.securities.balance_amount / 100000000);
// 黑金主题色
const gold = '#D4AF37';
const goldLight = '#F4D03F';
const textColor = 'rgba(255, 255, 255, 0.85)';
const textMuted = 'rgba(255, 255, 255, 0.5)';
const borderColor = 'rgba(212, 175, 55, 0.2)';
return {
backgroundColor: 'transparent',
title: {
text: '融资融券余额走势',
left: 'center',
textStyle: {
color: gold,
fontSize: 16,
fontWeight: 'bold',
},
},
tooltip: {
trigger: 'axis',
backgroundColor: 'rgba(26, 26, 46, 0.95)',
borderColor: gold,
borderWidth: 1,
textStyle: {
color: textColor,
},
formatter: (params: unknown) => {
const paramsArr = params as { name: string; marker: string; seriesName: string; value: number }[];
let result = `<span style="color: ${gold}">${paramsArr[0].name}</span><br/>`;
paramsArr.forEach((param) => {
result += `${param.marker} ${param.seriesName}: <span style="color: ${goldLight}; font-weight: bold">${param.value.toFixed(2)}亿</span><br/>`;
});
return result;
},
},
legend: {
data: ['融资余额', '融券余额'],
bottom: 10,
textStyle: {
color: textColor,
},
},
grid: {
left: '3%',
right: '4%',
bottom: '15%',
containLabel: true,
},
xAxis: {
type: 'category',
boundaryGap: false,
data: dates,
axisLine: { lineStyle: { color: borderColor } },
axisLabel: { color: textMuted },
splitLine: { show: false },
},
yAxis: {
type: 'value',
name: '金额(亿)',
nameTextStyle: { color: textMuted },
splitLine: {
lineStyle: {
color: borderColor,
type: 'dashed',
},
},
axisLine: { lineStyle: { color: borderColor } },
axisLabel: { color: textMuted },
},
series: [
{
name: '融资余额',
type: 'line',
smooth: true,
symbol: 'circle',
symbolSize: 8,
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(212, 175, 55, 0.4)' },
{ offset: 1, color: 'rgba(212, 175, 55, 0.05)' },
],
},
},
lineStyle: {
color: gold,
width: 2,
shadowBlur: 10,
shadowColor: 'rgba(212, 175, 55, 0.5)',
},
itemStyle: {
color: gold,
borderColor: goldLight,
borderWidth: 2,
},
data: financing,
},
{
name: '融券余额',
type: 'line',
smooth: true,
symbol: 'diamond',
symbolSize: 8,
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(255, 149, 0, 0.4)' },
{ offset: 1, color: 'rgba(255, 149, 0, 0.05)' },
],
},
},
lineStyle: {
color: '#FF9500',
width: 2,
shadowBlur: 10,
shadowColor: 'rgba(255, 149, 0, 0.5)',
},
itemStyle: {
color: '#FF9500',
borderColor: '#FFB347',
borderWidth: 2,
},
data: securities,
},
],
};
};
/** /**
* 生成股权质押图表配置 * 生成股权质押图表配置
*/ */
@@ -694,5 +842,6 @@ export default {
getKLineOption, getKLineOption,
getMinuteKLineOption, getMinuteKLineOption,
getFundingOption, getFundingOption,
getFundingDarkGoldOption,
getPledgeOption, getPledgeOption,
}; };