更新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
// 涨幅分析模态框组件
// 涨幅分析模态框组件 - FUI 科幻风格
import React from 'react';
import {
@@ -14,172 +14,446 @@ import {
Box,
Heading,
Text,
Tag,
Badge,
Icon,
} from '@chakra-ui/react';
import { ExternalLinkIcon } from '@chakra-ui/icons';
import { FileText, TrendingUp, Building2, Newspaper, BookOpen } from 'lucide-react';
import MarkdownRenderer from './MarkdownRenderer';
import { formatNumber } from '../utils/formatUtils';
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 {
analysis: RiseAnalysis;
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 (
<VStack align="stretch" spacing={4}>
{/* 头部信息 */}
<Box>
<Heading size="md" mb={2}>
{analysis.stock_name} ({analysis.stock_code})
</Heading>
<HStack spacing={4} mb={4}>
<Tag colorScheme="blue">: {analysis.trade_date}</Tag>
<Tag colorScheme="red">: {analysis.rise_rate}%</Tag>
<Tag colorScheme="green">: {analysis.close_price}</Tag>
{/* 头部信息 - FUI 风格 */}
<Box
position="relative"
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>
<FUIBadge color={FUI.goldLight}>{analysis.stock_code}</FUIBadge>
</HStack>
{/* 数据标签 */}
<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>
</Box>
{/* 主营业务 */}
{analysis.main_business && (
<Box p={4} bg="gray.50" borderRadius="md">
<Heading size="sm" mb={2} color={theme.primary}>
</Heading>
<Text color={theme.textPrimary}>{analysis.main_business}</Text>
</Box>
<FUISection title="主营业务" icon={Building2} color={FUI.cyan}>
<Text>{analysis.main_business}</Text>
</FUISection>
)}
{/* 详细分析 */}
{analysis.rise_reason_detail && (
<Box p={4} bg="purple.50" borderRadius="md">
<Heading size="sm" mb={2} color={theme.primary}>
</Heading>
<MarkdownRenderer theme={theme}>{analysis.rise_reason_detail}</MarkdownRenderer>
</Box>
<FUISection title="详细分析" icon={FileText} color={FUI.purple}>
<Box
sx={{
'& p': { color: FUI.textSecondary, mb: 2 },
'& 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>
</FUISection>
)}
{/* 相关公告 */}
{analysis.announcements && analysis.announcements !== '[]' && (
<Box p={4} bg="orange.50" borderRadius="md">
<Heading size="sm" mb={2} color={theme.primary}>
</Heading>
<MarkdownRenderer theme={theme}>{analysis.announcements}</MarkdownRenderer>
</Box>
<FUISection title="相关公告" icon={Newspaper} color={FUI.orange}>
<Box
sx={{
'& p': { color: FUI.textSecondary, mb: 2 },
'& strong': { color: FUI.textPrimary },
'& a': { color: FUI.gold },
}}
>
<MarkdownRenderer>{analysis.announcements}</MarkdownRenderer>
</Box>
</FUISection>
)}
{/* 研报引用 */}
{analysis.verification_reports && analysis.verification_reports.length > 0 && (
<Box p={4} bg="blue.50" borderRadius="md">
<Heading size="sm" mb={3} color={theme.primary}>
<HStack spacing={2}>
<Icon as={ExternalLinkIcon} />
<Text> ({analysis.verification_reports.length})</Text>
</HStack>
</Heading>
<FUISection title={`研报引用 (${analysis.verification_reports.length})`} icon={BookOpen} color={FUI.gold}>
<VStack spacing={3} align="stretch">
{analysis.verification_reports.map((report, reportIdx) => (
<Box
key={reportIdx}
p={3}
bg="white"
bg="rgba(0, 0, 0, 0.3)"
borderRadius="md"
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 spacing={2}>
<Badge colorScheme="blue" fontSize="xs">
<HStack justify="space-between" mb={2} flexWrap="wrap" gap={2}>
<HStack spacing={2} flexWrap="wrap">
<FUIBadge color={FUI.cyan}>
{report.publisher || '未知机构'}
</Badge>
</FUIBadge>
{report.match_score && (
<Badge
colorScheme={
<FUIBadge
color={
report.match_score === '好'
? 'green'
? FUI.green
: report.match_score === '中'
? 'yellow'
: 'gray'
? FUI.orange
: FUI.textMuted
}
fontSize="xs"
glow={report.match_score === '好'}
>
: {report.match_score}
</Badge>
: {report.match_score}
</FUIBadge>
)}
{report.match_ratio != null && report.match_ratio > 0 && (
<Badge colorScheme="purple" fontSize="xs">
<FUIBadge color={FUI.purple}>
{(report.match_ratio * 100).toFixed(0)}%
</Badge>
</FUIBadge>
)}
</HStack>
{report.declare_date && (
<Text fontSize="xs" color={theme.textMuted}>
<Text fontSize="xs" color={FUI.textMuted} fontFamily="mono">
{report.declare_date.substring(0, 10)}
</Text>
)}
</HStack>
{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}
</Text>
)}
{report.author && (
<Text fontSize="xs" color={theme.textMuted} mb={2}>
: {report.author}
<Text fontSize="xs" color={FUI.textMuted} mb={2}>
: <Text as="span" color={FUI.goldLight}>{report.author}</Text>
</Text>
)}
{report.verification_item && (
<Box p={2} bg="yellow.50" borderRadius="sm" mb={2}>
<Text fontSize="xs" color={theme.textMuted}>
<strong>:</strong> {report.verification_item}
<Box
p={2}
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>
</Box>
)}
{report.content && (
<Text fontSize="sm" color={theme.textSecondary} noOfLines={4}>
<Text fontSize="sm" color={FUI.textMuted} noOfLines={4}>
{report.content}
</Text>
)}
</Box>
))}
</VStack>
</Box>
</FUISection>
)}
{/* 底部统计 */}
<Box mt={4}>
<Text fontSize="sm" color={theme.textMuted}>
: {formatNumber(analysis.volume)} | : {formatNumber(analysis.amount)} | :{' '}
{analysis.update_time || analysis.create_time || '-'}
</Text>
{/* 底部统计 - FUI 风格 */}
<Box
mt={2}
p={3}
bg="rgba(0, 0, 0, 0.2)"
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>
</VStack>
);
};
/**
* 涨幅分析模态框组件
* 涨幅分析模态框组件 - FUI 科幻风格
*/
const AnalysisModal: React.FC<AnalysisModalProps> = ({ isOpen, onClose, content, theme }) => {
const AnalysisModal: React.FC<AnalysisModalProps> = ({ isOpen, onClose, content }) => {
return (
<Modal isOpen={isOpen} onClose={onClose} size="4xl" scrollBehavior="inside">
<ModalOverlay />
<ModalContent bg={theme.bgCard}>
<ModalHeader color={theme.textPrimary}></ModalHeader>
<ModalCloseButton />
<ModalBody pb={6}>{content}</ModalBody>
<Modal isOpen={isOpen} onClose={onClose} size="4xl" scrollBehavior="inside" isCentered>
<ModalOverlay
bg="rgba(0, 0, 0, 0.8)"
backdropFilter="blur(8px)"
/>
<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>
</Modal>
);

View File

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