更新Company页面的UI为FUI风格

This commit is contained in:
2025-12-17 19:31:55 +08:00
parent 854aadcbc7
commit c393e31eec
3 changed files with 383 additions and 87 deletions

View File

@@ -1,5 +1,5 @@
// src/views/Company/components/MarketDataView/components/AnalysisModal.tsx // src/views/Company/components/MarketDataView/components/AnalysisModal.tsx
// 涨幅分析模态框组件 // 涨幅分析模态框组件 - FUI 科幻风格
import React from 'react'; import React from 'react';
import { import {
@@ -14,172 +14,446 @@ import {
Box, Box,
Heading, Heading,
Text, Text,
Tag,
Badge,
Icon, Icon,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { ExternalLinkIcon } from '@chakra-ui/icons'; import { ExternalLinkIcon } from '@chakra-ui/icons';
import { FileText, TrendingUp, Building2, Newspaper, BookOpen } from 'lucide-react';
import MarkdownRenderer from './MarkdownRenderer'; import MarkdownRenderer from './MarkdownRenderer';
import { formatNumber } from '../utils/formatUtils'; import { formatNumber } from '../utils/formatUtils';
import type { AnalysisModalProps, RiseAnalysis, Theme } from '../types'; import type { AnalysisModalProps, RiseAnalysis, Theme } from '../types';
// FUI 风格颜色常量
const FUI = {
gold: '#D4AF37',
goldLight: 'rgba(212, 175, 55, 0.8)',
goldDim: 'rgba(212, 175, 55, 0.4)',
red: '#FF4444',
green: '#00C851',
cyan: '#00BCD4',
purple: '#9C27B0',
orange: '#FF9800',
bgDeep: '#0A0A14',
bgPrimary: '#0F0F1A',
bgElevated: '#1A1A2E',
bgCard: 'rgba(26, 26, 46, 0.95)',
textPrimary: 'rgba(255, 255, 255, 0.95)',
textSecondary: 'rgba(255, 255, 255, 0.75)',
textMuted: 'rgba(255, 255, 255, 0.5)',
border: 'rgba(212, 175, 55, 0.2)',
borderHover: 'rgba(212, 175, 55, 0.4)',
};
/** /**
* 涨幅分析内容组件 * FUI 风格标签组件
*/
const FUITag: React.FC<{
children: React.ReactNode;
color?: string;
icon?: React.ElementType;
}> = ({ children, color = FUI.gold, icon }) => (
<HStack
spacing={1.5}
px={2.5}
py={1}
bg={`${color}15`}
border="1px solid"
borderColor={`${color}40`}
borderRadius="md"
fontSize="xs"
color={color}
fontFamily="mono"
>
{icon && <Icon as={icon} boxSize={3} />}
<Text>{children}</Text>
</HStack>
);
/**
* FUI 风格徽章组件
*/
const FUIBadge: React.FC<{
children: React.ReactNode;
color?: string;
glow?: boolean;
}> = ({ children, color = FUI.gold, glow = false }) => (
<Box
display="inline-flex"
px={2}
py={0.5}
bg={`${color}20`}
border="1px solid"
borderColor={`${color}50`}
borderRadius="sm"
fontSize="2xs"
color={color}
fontWeight="medium"
boxShadow={glow ? `0 0 8px ${color}40` : undefined}
>
{children}
</Box>
);
/**
* FUI 风格区块组件
*/
const FUISection: React.FC<{
title: string;
icon: React.ElementType;
color?: string;
children: React.ReactNode;
}> = ({ title, icon, color = FUI.gold, children }) => (
<Box
position="relative"
p={4}
bg="rgba(0, 0, 0, 0.3)"
borderRadius="lg"
border="1px solid"
borderColor={FUI.border}
overflow="hidden"
>
{/* 顶部发光线 */}
<Box
position="absolute"
top={0}
left="10%"
right="10%"
h="1px"
bg={`linear-gradient(90deg, transparent, ${color}60, transparent)`}
/>
{/* 左侧装饰条 */}
<Box
position="absolute"
left={0}
top="20%"
bottom="20%"
w="2px"
bg={`linear-gradient(180deg, transparent, ${color}, transparent)`}
/>
{/* 标题 */}
<HStack spacing={2} mb={3}>
<Icon
as={icon}
boxSize={4}
color={color}
filter={`drop-shadow(0 0 4px ${color})`}
/>
<Heading
size="sm"
color={color}
letterSpacing="wide"
textShadow={`0 0 10px ${color}40`}
>
{title}
</Heading>
</HStack>
{/* 内容 */}
<Box color={FUI.textSecondary} fontSize="sm" lineHeight="tall">
{children}
</Box>
</Box>
);
/**
* 涨幅分析内容组件 - FUI 风格
*/ */
interface AnalysisContentProps { interface AnalysisContentProps {
analysis: RiseAnalysis; analysis: RiseAnalysis;
theme: Theme; theme: Theme;
} }
export const AnalysisContent: React.FC<AnalysisContentProps> = ({ analysis, theme }) => { export const AnalysisContent: React.FC<AnalysisContentProps> = ({ analysis }) => {
const riseColor = parseFloat(String(analysis.rise_rate)) >= 0 ? FUI.red : FUI.green;
return ( return (
<VStack align="stretch" spacing={4}> <VStack align="stretch" spacing={4}>
{/* 头部信息 */} {/* 头部信息 - FUI 风格 */}
<Box> <Box
<Heading size="md" mb={2}> position="relative"
{analysis.stock_name} ({analysis.stock_code}) p={4}
bg="linear-gradient(135deg, rgba(212, 175, 55, 0.1) 0%, rgba(0, 0, 0, 0.3) 100%)"
borderRadius="lg"
border="1px solid"
borderColor={FUI.borderHover}
>
{/* 角落装饰 */}
<Box position="absolute" top={2} left={2} w={3} h={3} borderTop="2px solid" borderLeft="2px solid" borderColor={FUI.goldDim} />
<Box position="absolute" top={2} right={2} w={3} h={3} borderTop="2px solid" borderRight="2px solid" borderColor={FUI.goldDim} />
<Box position="absolute" bottom={2} left={2} w={3} h={3} borderBottom="2px solid" borderLeft="2px solid" borderColor={FUI.goldDim} />
<Box position="absolute" bottom={2} right={2} w={3} h={3} borderBottom="2px solid" borderRight="2px solid" borderColor={FUI.goldDim} />
{/* 股票名称 */}
<HStack spacing={3} mb={3}>
<Heading
size="lg"
color={FUI.gold}
letterSpacing="wider"
textShadow={`0 0 20px ${FUI.gold}40`}
>
{analysis.stock_name}
</Heading> </Heading>
<HStack spacing={4} mb={4}> <FUIBadge color={FUI.goldLight}>{analysis.stock_code}</FUIBadge>
<Tag colorScheme="blue">: {analysis.trade_date}</Tag> </HStack>
<Tag colorScheme="red">: {analysis.rise_rate}%</Tag>
<Tag colorScheme="green">: {analysis.close_price}</Tag> {/* 数据标签 */}
<HStack spacing={3} flexWrap="wrap">
<FUITag color={FUI.cyan}>: {analysis.trade_date}</FUITag>
<FUITag color={riseColor} icon={TrendingUp}>
: {analysis.rise_rate}%
</FUITag>
<FUITag color={FUI.gold}>
: ¥{analysis.close_price}
</FUITag>
</HStack> </HStack>
</Box> </Box>
{/* 主营业务 */} {/* 主营业务 */}
{analysis.main_business && ( {analysis.main_business && (
<Box p={4} bg="gray.50" borderRadius="md"> <FUISection title="主营业务" icon={Building2} color={FUI.cyan}>
<Heading size="sm" mb={2} color={theme.primary}> <Text>{analysis.main_business}</Text>
</FUISection>
</Heading>
<Text color={theme.textPrimary}>{analysis.main_business}</Text>
</Box>
)} )}
{/* 详细分析 */} {/* 详细分析 */}
{analysis.rise_reason_detail && ( {analysis.rise_reason_detail && (
<Box p={4} bg="purple.50" borderRadius="md"> <FUISection title="详细分析" icon={FileText} color={FUI.purple}>
<Heading size="sm" mb={2} color={theme.primary}> <Box
sx={{
</Heading> '& p': { color: FUI.textSecondary, mb: 2 },
<MarkdownRenderer theme={theme}>{analysis.rise_reason_detail}</MarkdownRenderer> '& strong': { color: FUI.textPrimary },
'& a': { color: FUI.gold, textDecoration: 'underline' },
'& ul, & ol': { pl: 4, color: FUI.textSecondary },
'& li': { mb: 1 },
}}
>
<MarkdownRenderer>{analysis.rise_reason_detail}</MarkdownRenderer>
</Box> </Box>
</FUISection>
)} )}
{/* 相关公告 */} {/* 相关公告 */}
{analysis.announcements && analysis.announcements !== '[]' && ( {analysis.announcements && analysis.announcements !== '[]' && (
<Box p={4} bg="orange.50" borderRadius="md"> <FUISection title="相关公告" icon={Newspaper} color={FUI.orange}>
<Heading size="sm" mb={2} color={theme.primary}> <Box
sx={{
</Heading> '& p': { color: FUI.textSecondary, mb: 2 },
<MarkdownRenderer theme={theme}>{analysis.announcements}</MarkdownRenderer> '& strong': { color: FUI.textPrimary },
'& a': { color: FUI.gold },
}}
>
<MarkdownRenderer>{analysis.announcements}</MarkdownRenderer>
</Box> </Box>
</FUISection>
)} )}
{/* 研报引用 */} {/* 研报引用 */}
{analysis.verification_reports && analysis.verification_reports.length > 0 && ( {analysis.verification_reports && analysis.verification_reports.length > 0 && (
<Box p={4} bg="blue.50" borderRadius="md"> <FUISection title={`研报引用 (${analysis.verification_reports.length})`} icon={BookOpen} color={FUI.gold}>
<Heading size="sm" mb={3} color={theme.primary}>
<HStack spacing={2}>
<Icon as={ExternalLinkIcon} />
<Text> ({analysis.verification_reports.length})</Text>
</HStack>
</Heading>
<VStack spacing={3} align="stretch"> <VStack spacing={3} align="stretch">
{analysis.verification_reports.map((report, reportIdx) => ( {analysis.verification_reports.map((report, reportIdx) => (
<Box <Box
key={reportIdx} key={reportIdx}
p={3} p={3}
bg="white" bg="rgba(0, 0, 0, 0.3)"
borderRadius="md" borderRadius="md"
border="1px solid" border="1px solid"
borderColor={theme.border} borderColor={FUI.border}
transition="all 0.2s"
_hover={{
borderColor: FUI.borderHover,
bg: 'rgba(212, 175, 55, 0.05)',
}}
> >
<HStack justify="space-between" mb={2}> <HStack justify="space-between" mb={2} flexWrap="wrap" gap={2}>
<HStack spacing={2}> <HStack spacing={2} flexWrap="wrap">
<Badge colorScheme="blue" fontSize="xs"> <FUIBadge color={FUI.cyan}>
{report.publisher || '未知机构'} {report.publisher || '未知机构'}
</Badge> </FUIBadge>
{report.match_score && ( {report.match_score && (
<Badge <FUIBadge
colorScheme={ color={
report.match_score === '好' report.match_score === '好'
? 'green' ? FUI.green
: report.match_score === '中' : report.match_score === '中'
? 'yellow' ? FUI.orange
: 'gray' : FUI.textMuted
} }
fontSize="xs" glow={report.match_score === '好'}
> >
: {report.match_score} : {report.match_score}
</Badge> </FUIBadge>
)} )}
{report.match_ratio != null && report.match_ratio > 0 && ( {report.match_ratio != null && report.match_ratio > 0 && (
<Badge colorScheme="purple" fontSize="xs"> <FUIBadge color={FUI.purple}>
{(report.match_ratio * 100).toFixed(0)}% {(report.match_ratio * 100).toFixed(0)}%
</Badge> </FUIBadge>
)} )}
</HStack> </HStack>
{report.declare_date && ( {report.declare_date && (
<Text fontSize="xs" color={theme.textMuted}> <Text fontSize="xs" color={FUI.textMuted} fontFamily="mono">
{report.declare_date.substring(0, 10)} {report.declare_date.substring(0, 10)}
</Text> </Text>
)} )}
</HStack> </HStack>
{report.report_title && ( {report.report_title && (
<Text fontWeight="bold" fontSize="sm" color={theme.textPrimary} mb={1}> <Text
fontWeight="bold"
fontSize="sm"
color={FUI.textPrimary}
mb={1}
_hover={{ color: FUI.gold }}
cursor="pointer"
>
{report.report_title} {report.report_title}
</Text> </Text>
)} )}
{report.author && ( {report.author && (
<Text fontSize="xs" color={theme.textMuted} mb={2}> <Text fontSize="xs" color={FUI.textMuted} mb={2}>
: {report.author} : <Text as="span" color={FUI.goldLight}>{report.author}</Text>
</Text> </Text>
)} )}
{report.verification_item && ( {report.verification_item && (
<Box p={2} bg="yellow.50" borderRadius="sm" mb={2}> <Box
<Text fontSize="xs" color={theme.textMuted}> p={2}
<strong>:</strong> {report.verification_item} bg="rgba(212, 175, 55, 0.1)"
borderRadius="sm"
border="1px solid"
borderColor="rgba(212, 175, 55, 0.2)"
mb={2}
>
<Text fontSize="xs" color={FUI.textSecondary}>
<Text as="span" color={FUI.gold} fontWeight="bold">:</Text>{' '}
{report.verification_item}
</Text> </Text>
</Box> </Box>
)} )}
{report.content && ( {report.content && (
<Text fontSize="sm" color={theme.textSecondary} noOfLines={4}> <Text fontSize="sm" color={FUI.textMuted} noOfLines={4}>
{report.content} {report.content}
</Text> </Text>
)} )}
</Box> </Box>
))} ))}
</VStack> </VStack>
</Box> </FUISection>
)} )}
{/* 底部统计 */} {/* 底部统计 - FUI 风格 */}
<Box mt={4}> <Box
<Text fontSize="sm" color={theme.textMuted}> mt={2}
: {formatNumber(analysis.volume)} | : {formatNumber(analysis.amount)} | :{' '} p={3}
{analysis.update_time || analysis.create_time || '-'} bg="rgba(0, 0, 0, 0.2)"
</Text> borderRadius="md"
border="1px solid"
borderColor={FUI.border}
>
<HStack spacing={4} justify="center" flexWrap="wrap" fontSize="xs" color={FUI.textMuted} fontFamily="mono">
<HStack spacing={1}>
<Text color={FUI.goldDim}></Text>
<Text color={FUI.textSecondary}>{formatNumber(analysis.volume)}</Text>
</HStack>
<Box w="1px" h={3} bg={FUI.border} />
<HStack spacing={1}>
<Text color={FUI.goldDim}></Text>
<Text color={FUI.textSecondary}>{formatNumber(analysis.amount)}</Text>
</HStack>
<Box w="1px" h={3} bg={FUI.border} />
<HStack spacing={1}>
<Text color={FUI.goldDim}></Text>
<Text color={FUI.textSecondary}>{analysis.update_time || analysis.create_time || '-'}</Text>
</HStack>
</HStack>
</Box> </Box>
</VStack> </VStack>
); );
}; };
/** /**
* 涨幅分析模态框组件 * 涨幅分析模态框组件 - FUI 科幻风格
*/ */
const AnalysisModal: React.FC<AnalysisModalProps> = ({ isOpen, onClose, content, theme }) => { const AnalysisModal: React.FC<AnalysisModalProps> = ({ isOpen, onClose, content }) => {
return ( return (
<Modal isOpen={isOpen} onClose={onClose} size="4xl" scrollBehavior="inside"> <Modal isOpen={isOpen} onClose={onClose} size="4xl" scrollBehavior="inside" isCentered>
<ModalOverlay /> <ModalOverlay
<ModalContent bg={theme.bgCard}> bg="rgba(0, 0, 0, 0.8)"
<ModalHeader color={theme.textPrimary}></ModalHeader> backdropFilter="blur(8px)"
<ModalCloseButton /> />
<ModalBody pb={6}>{content}</ModalBody> <ModalContent
bg="linear-gradient(145deg, rgba(26, 26, 46, 0.98) 0%, rgba(15, 15, 26, 0.99) 100%)"
border="1px solid"
borderColor={FUI.border}
borderRadius="xl"
boxShadow={`0 0 40px rgba(0, 0, 0, 0.5), 0 0 20px ${FUI.gold}20, inset 0 1px 0 rgba(255, 255, 255, 0.05)`}
overflow="hidden"
position="relative"
>
{/* 顶部发光线 */}
<Box
position="absolute"
top={0}
left="20%"
right="20%"
h="1px"
bg={`linear-gradient(90deg, transparent, ${FUI.gold}80, transparent)`}
/>
{/* 角落装饰 */}
<Box position="absolute" top={3} left={3} w={4} h={4} borderTop="2px solid" borderLeft="2px solid" borderColor={FUI.goldDim} />
<Box position="absolute" top={3} right={3} w={4} h={4} borderTop="2px solid" borderRight="2px solid" borderColor={FUI.goldDim} />
<Box position="absolute" bottom={3} left={3} w={4} h={4} borderBottom="2px solid" borderLeft="2px solid" borderColor={FUI.goldDim} />
<Box position="absolute" bottom={3} right={3} w={4} h={4} borderBottom="2px solid" borderRight="2px solid" borderColor={FUI.goldDim} />
<ModalHeader
color={FUI.gold}
fontSize="lg"
fontWeight="bold"
letterSpacing="wider"
textShadow={`0 0 15px ${FUI.gold}40`}
borderBottom="1px solid"
borderColor={FUI.border}
bg="rgba(0, 0, 0, 0.2)"
>
<HStack spacing={2}>
<Icon as={TrendingUp} boxSize={5} filter={`drop-shadow(0 0 4px ${FUI.gold})`} />
<Text></Text>
</HStack>
</ModalHeader>
<ModalCloseButton
color={FUI.textMuted}
_hover={{
color: FUI.gold,
bg: 'rgba(212, 175, 55, 0.1)',
}}
/>
<ModalBody
pb={6}
pt={4}
css={{
'&::-webkit-scrollbar': {
width: '6px',
},
'&::-webkit-scrollbar-track': {
background: 'rgba(0, 0, 0, 0.2)',
},
'&::-webkit-scrollbar-thumb': {
background: FUI.goldDim,
borderRadius: '3px',
},
'&::-webkit-scrollbar-thumb:hover': {
background: FUI.gold,
},
}}
>
{content}
</ModalBody>
</ModalContent> </ModalContent>
</Modal> </Modal>
); );

View File

@@ -1,22 +1,32 @@
// src/views/Company/components/MarketDataView/components/MarkdownRenderer.tsx // src/views/Company/components/MarketDataView/components/MarkdownRenderer.tsx
// Markdown 渲染组件 // Markdown 渲染组件 - 支持 FUI 科幻风格
import React from 'react'; import React from 'react';
import { Box } from '@chakra-ui/react'; import { Box } from '@chakra-ui/react';
import ReactMarkdown from 'react-markdown'; import ReactMarkdown from 'react-markdown';
import type { MarkdownRendererProps } from '../types'; import type { MarkdownRendererProps } from '../types';
// FUI 默认主题(黑金风格)
const FUI_THEME = {
primary: '#D4AF37',
textPrimary: 'rgba(255, 255, 255, 0.95)',
textSecondary: 'rgba(255, 255, 255, 0.75)',
};
/** /**
* Markdown 渲染组件 * Markdown 渲染组件
* 提供统一的 Markdown 样式 * 提供统一的 Markdown 样式,支持 FUI 风格
*/ */
const MarkdownRenderer: React.FC<MarkdownRendererProps> = ({ children, theme }) => { const MarkdownRenderer: React.FC<MarkdownRendererProps> = ({ children, theme }) => {
// 使用传入的主题或默认 FUI 主题
const colors = theme || FUI_THEME;
return ( return (
<Box <Box
color={theme.textPrimary} color={colors.textPrimary}
sx={{ sx={{
'& h1, & h2, & h3, & h4, & h5, & h6': { '& h1, & h2, & h3, & h4, & h5, & h6': {
color: theme.primary, color: colors.primary,
marginTop: 4, marginTop: 4,
marginBottom: 2, marginBottom: 2,
fontWeight: 'bold', fontWeight: 'bold',
@@ -37,23 +47,35 @@ const MarkdownRenderer: React.FC<MarkdownRendererProps> = ({ children, theme })
}, },
'& strong': { '& strong': {
fontWeight: 'bold', fontWeight: 'bold',
color: theme.textSecondary, color: colors.textSecondary,
}, },
'& em': { '& em': {
fontStyle: 'italic', fontStyle: 'italic',
}, },
'& code': { '& code': {
backgroundColor: 'rgba(0,0,0,0.05)', backgroundColor: 'rgba(212, 175, 55, 0.1)',
padding: '2px 4px', padding: '2px 6px',
borderRadius: '4px', borderRadius: '4px',
fontSize: '0.9em', fontSize: '0.9em',
color: '#D4AF37',
border: '1px solid rgba(212, 175, 55, 0.2)',
}, },
'& blockquote': { '& blockquote': {
borderLeft: `3px solid ${theme.primary}`, borderLeft: `3px solid ${colors.primary}`,
paddingLeft: 4, paddingLeft: 4,
marginLeft: 2, marginLeft: 2,
fontStyle: 'italic', fontStyle: 'italic',
opacity: 0.9, opacity: 0.9,
backgroundColor: 'rgba(212, 175, 55, 0.05)',
borderRadius: '0 4px 4px 0',
padding: 3,
},
'& a': {
color: '#D4AF37',
textDecoration: 'underline',
_hover: {
color: '#F4D03F',
},
}, },
}} }}
> >

View File

@@ -262,7 +262,7 @@ export interface ThemedCardProps {
*/ */
export interface MarkdownRendererProps { export interface MarkdownRendererProps {
children: string; children: string;
theme: Theme; theme?: Theme; // 可选,默认使用 FUI 黑金主题
} }
/** /**