import React, { useState, useEffect } from 'react'; import { Box, VStack, HStack, Text, Badge, Card, CardBody, CardHeader, Heading, SimpleGrid, Divider, Spinner, Center, Alert, AlertIcon, Tabs, TabList, TabPanels, Tab, TabPanel, Button, useColorModeValue, Tag, TagLabel, Icon, Tooltip, Flex, Grid, GridItem, useToast, Table, Thead, Tbody, Tr, Th, Td, TableContainer, IconButton, Skeleton, SkeletonText, Progress, Stack, Stat, StatLabel, StatNumber, StatHelpText, Container, Wrap, WrapItem, List, ListItem, ListIcon, Accordion, AccordionItem, AccordionButton, AccordionPanel, AccordionIcon, Fade, ScaleFade, useDisclosure, Modal, ModalOverlay, ModalContent, ModalHeader, ModalFooter, ModalBody, ModalCloseButton, Circle, Square, Avatar, AvatarGroup, Input, InputGroup, InputLeftElement, Link, Breadcrumb, BreadcrumbItem, BreadcrumbLink, Image, Code, chakra } from '@chakra-ui/react'; import { FaBuilding, FaMapMarkerAlt, FaChartLine, FaLightbulb, FaRocket, FaNetworkWired, FaChevronDown, FaChevronUp, FaChevronLeft, FaChevronRight, FaCog, FaTrophy, FaShieldAlt, FaBrain, FaChartPie, FaHistory, FaCheckCircle, FaExclamationCircle, FaArrowUp, FaArrowDown, FaArrowRight, FaArrowLeft, FaLink, FaStar, FaUserTie, FaIndustry, FaDollarSign, FaBalanceScale, FaChartBar, FaEye, FaFlask, FaHandshake, FaUsers, FaClock, FaCalendarAlt, FaCircle, FaGlobe, FaEnvelope, FaPhone, FaFax, FaBriefcase, FaUniversity, FaGraduationCap, FaVenusMars, FaPassport, FaFileAlt, FaNewspaper, FaBullhorn, FaUserShield, FaShareAlt, FaSitemap, FaSearch, FaDownload, FaExternalLinkAlt, FaInfoCircle, FaCrown, FaCertificate, FaAward, FaExpandAlt, FaCompressAlt, FaGavel, FaFire } from 'react-icons/fa'; import { RepeatIcon, InfoIcon, ChevronRightIcon, TimeIcon, EmailIcon, PhoneIcon, ExternalLinkIcon, AttachmentIcon, CalendarIcon, SearchIcon, WarningIcon, CheckIcon } from '@chakra-ui/icons'; import ReactECharts from 'echarts-for-react'; import { logger } from '../../utils/logger'; import { getApiBase } from '../../utils/apiConfig'; // API配置 const API_BASE_URL = getApiBase(); // 格式化工具 const formatUtils = { formatCurrency: (value) => { if (!value && value !== 0) return '-'; const absValue = Math.abs(value); if (absValue >= 100000000) { return (value / 100000000).toFixed(2) + '亿元'; } else if (absValue >= 10000) { return (value / 10000).toFixed(2) + '万元'; } return value.toFixed(2) + '元'; }, formatRegisteredCapital: (value) => { // 注册资本字段,数据库存储的是万元为单位的数值 if (!value && value !== 0) return '-'; const absValue = Math.abs(value); if (absValue >= 100000) { // 10亿万元 = 10亿元 return (value / 10000).toFixed(2) + '亿元'; } return value.toFixed(2) + '万元'; }, formatBusinessRevenue: (value, unit) => { // 业务收入格式化,考虑数据库中的单位字段 if (!value && value !== 0) return '-'; if (unit) { // 根据数据库中的单位进行智能格式化 if (unit === '元') { // 元为单位时,自动转换为合适的单位显示 const absValue = Math.abs(value); if (absValue >= 100000000) { return (value / 100000000).toFixed(2) + '亿元'; } else if (absValue >= 10000) { return (value / 10000).toFixed(2) + '万元'; } return value.toFixed(0) + '元'; } else if (unit === '万元') { // 万元为单位时,可能需要转换为亿元 const absValue = Math.abs(value); if (absValue >= 10000) { return (value / 10000).toFixed(2) + '亿元'; } return value.toFixed(2) + '万元'; } else if (unit === '亿元') { // 亿元为单位时,直接显示 return value.toFixed(2) + '亿元'; } else { // 其他单位直接显示 return value.toFixed(2) + unit; } } // 没有单位字段时,使用默认的货币格式化 const absValue = Math.abs(value); if (absValue >= 100000000) { return (value / 100000000).toFixed(2) + '亿元'; } else if (absValue >= 10000) { return (value / 10000).toFixed(2) + '万元'; } return value.toFixed(2) + '元'; }, formatPercentage: (value) => { if (!value && value !== 0) return '-'; return value.toFixed(2) + '%'; }, formatNumber: (value) => { if (!value && value !== 0) return '-'; return value.toLocaleString('zh-CN'); }, formatDate: (dateString) => { if (!dateString) return '-'; return new Date(dateString).toLocaleDateString('zh-CN'); }, formatShares: (value) => { if (!value && value !== 0) return '-'; const absValue = Math.abs(value); if (absValue >= 100000000) { return (value / 100000000).toFixed(2) + '亿股'; } else if (absValue >= 10000) { return (value / 10000).toFixed(2) + '万股'; } return value.toFixed(0) + '股'; } }; // 免责声明组件 const DisclaimerBox = () => { return ( 免责声明 本内容由AI模型基于新闻、公告、研报等公开信息自动分析和生成,未经许可严禁转载。 所有内容仅供参考,不构成任何投资建议,请投资者注意风险,独立审慎决策。 ); }; // 评分进度条组件 const ScoreBar = ({ label, score, maxScore = 100, colorScheme = 'blue', icon }) => { const percentage = (score / maxScore) * 100; const getColorScheme = () => { if (percentage >= 80) return 'purple'; if (percentage >= 60) return 'blue'; if (percentage >= 40) return 'yellow'; return 'orange'; }; return ( {icon && } {label} {score || 0} ); }; // 业务结构树形图组件 const BusinessTreeItem = ({ business, depth = 0 }) => { const bgColor = useColorModeValue('gray.50', 'gray.700'); const borderColor = useColorModeValue('gray.200', 'gray.600'); const profitColor = business.financial_metrics?.profit_growth > 0 ? 'red.500' : 'green.500'; return ( 0 ? `4px solid` : 'none'} borderLeftColor="blue.400" borderRadius="md" mb={2} _hover={{ shadow: 'md' }} transition="all 0.2s" > {business.business_name} {business.financial_metrics?.revenue_ratio > 30 && ( 核心业务 )} 营收占比: {formatUtils.formatPercentage(business.financial_metrics?.revenue_ratio)} 毛利率: {formatUtils.formatPercentage(business.financial_metrics?.gross_margin)} {business.growth_metrics?.revenue_growth && ( 0 ? 'red' : 'green'}> 增长: {business.growth_metrics.revenue_growth > 0 ? '+' : ''}{formatUtils.formatPercentage(business.growth_metrics.revenue_growth)} )} {(() => { // 优先使用business.revenue,如果没有则使用financial_metrics.revenue const revenue = business.revenue || business.financial_metrics?.revenue; const unit = business.revenue_unit; if (revenue || revenue === 0) { return formatUtils.formatBusinessRevenue(revenue, unit); } return '-'; })()} 营业收入 ); }; // 产业链节点卡片 const ValueChainNodeCard = ({ node, isCompany = false, level = 0 }) => { const { isOpen, onOpen, onClose } = useDisclosure(); const [relatedCompanies, setRelatedCompanies] = useState([]); const [loadingRelated, setLoadingRelated] = useState(false); const toast = useToast(); const getColorScheme = () => { if (isCompany) return 'blue'; if (level < 0) return 'orange'; if (level > 0) return 'green'; return 'gray'; }; const colorScheme = getColorScheme(); const bgColor = useColorModeValue(`${colorScheme}.50`, `${colorScheme}.900`); const borderColor = useColorModeValue(`${colorScheme}.200`, `${colorScheme}.600`); const getNodeTypeIcon = (type) => { const icons = { 'company': FaBuilding, 'supplier': FaHandshake, 'customer': FaUserTie, 'product': FaIndustry, 'service': FaCog, 'channel': FaNetworkWired, 'raw_material': FaFlask }; return icons[type] || FaBuilding; }; const getImportanceColor = (score) => { if (score >= 80) return 'red'; if (score >= 60) return 'orange'; if (score >= 40) return 'yellow'; return 'green'; }; // 获取相关公司 const fetchRelatedCompanies = async () => { setLoadingRelated(true); try { const response = await fetch( `${API_BASE_URL}/api/company/value-chain/related-companies?node_name=${encodeURIComponent(node.node_name)}` ); const data = await response.json(); if (data.success) { setRelatedCompanies(data.data || []); } else { toast({ title: '获取相关公司失败', description: data.message, status: 'error', duration: 3000, isClosable: true, }); } } catch (error) { logger.error('ValueChainNodeCard', 'fetchRelatedCompanies', error, { node_name: node.node_name }); toast({ title: '获取相关公司失败', description: error.message, status: 'error', duration: 3000, isClosable: true, }); } finally { setLoadingRelated(false); } }; const handleCardClick = () => { onOpen(); if (relatedCompanies.length === 0) { fetchRelatedCompanies(); } }; return ( <> {isCompany && ( 核心企业 )} {node.importance_score >= 70 && ( )} {node.node_name} {node.node_description && ( {node.node_description} )} {node.node_type} {node.market_share && ( 份额 {node.market_share}% )} {(node.importance_score || node.importance_score === 0) && ( 重要度 {node.importance_score} )} {node.node_name} {node.node_type} {isCompany && 核心企业} {node.node_description && ( 节点描述 {node.node_description} )} 重要度评分 {node.importance_score || 0} {node.market_share && ( 市场份额 {node.market_share}% )} {node.dependency_degree && ( 依赖程度 {node.dependency_degree}% 50 ? 'orange' : 'green'} borderRadius="full" /> )} {/* 相关公司列表 */} 相关公司 {loadingRelated && } {loadingRelated ? (
) : relatedCompanies.length > 0 ? ( {relatedCompanies.map((company, idx) => { // 获取节点层级标签 const getLevelLabel = (level) => { if (level < 0) return { text: '上游', color: 'orange' }; if (level === 0) return { text: '核心', color: 'blue' }; if (level > 0) return { text: '下游', color: 'green' }; return { text: '未知', color: 'gray' }; }; const levelInfo = getLevelLabel(company.node_info?.node_level); return ( {/* 公司基本信息 */} {company.stock_name} {company.stock_code} {levelInfo.text} {company.node_info?.node_type && ( {company.node_info.node_type} )} {company.company_name && ( {company.company_name} )} } variant="ghost" colorScheme="blue" onClick={() => { window.location.href = `/company?stock_code=${company.stock_code}`; }} aria-label="查看公司详情" /> {/* 节点描述 */} {company.node_info?.node_description && ( {company.node_info.node_description} )} {/* 节点指标 */} {(company.node_info?.importance_score || company.node_info?.market_share || company.node_info?.dependency_degree) && ( {company.node_info.importance_score && ( 重要度: {company.node_info.importance_score} )} {company.node_info.market_share && ( 市场份额: {company.node_info.market_share}% )} {company.node_info.dependency_degree && ( 依赖度: {company.node_info.dependency_degree}% )} )} {/* 流向关系 */} {company.relationships && company.relationships.length > 0 && ( 产业链关系: {company.relationships.map((rel, ridx) => ( {rel.role === 'source' ? '流向' : '来自'} {rel.connected_node} {rel.relationship_desc && ( {rel.relationship_desc} )} {rel.flow_ratio && ( {rel.flow_ratio}% )} ))} )} ); })} ) : (
暂无相关公司
)}
); }; // 关键因素卡片 const KeyFactorCard = ({ factor }) => { const impactColor = { positive: 'red', negative: 'green', neutral: 'gray', mixed: 'yellow' }[factor.impact_direction] || 'gray'; const bgColor = useColorModeValue('white', 'gray.800'); const borderColor = useColorModeValue('gray.200', 'gray.600'); return ( {factor.factor_name} {factor.impact_direction === 'positive' ? '正面' : factor.impact_direction === 'negative' ? '负面' : factor.impact_direction === 'mixed' ? '混合' : '中性'} {factor.factor_value} {factor.factor_unit && ` ${factor.factor_unit}`} {factor.year_on_year && ( 0 ? 'red' : 'green'}> 0 ? FaArrowUp : FaArrowDown} mr={1} boxSize={3} /> {Math.abs(factor.year_on_year)}% )} {factor.factor_desc && ( {factor.factor_desc} )} 影响权重: {factor.impact_weight} {factor.report_period && ( {factor.report_period} )} ); }; // 时间线组件 const TimelineComponent = ({ events }) => { const [selectedEvent, setSelectedEvent] = useState(null); const { isOpen, onOpen, onClose } = useDisclosure(); const handleEventClick = (event) => { setSelectedEvent(event); onOpen(); }; return ( <> {events.map((event, idx) => { const isPositive = event.impact_metrics?.is_positive; const iconColor = isPositive ? 'red.500' : 'green.500'; const bgColor = useColorModeValue( isPositive ? 'red.50' : 'green.50', isPositive ? 'red.900' : 'green.900' ); return ( handleEventClick(event)} _hover={{ shadow: 'lg', transform: 'translateX(4px)' }} transition="all 0.3s ease" > {event.event_title} {event.event_date} {event.event_type} {event.event_desc} 影响度: 70 ? 'red' : 'orange'} borderRadius="full" /> {event.impact_metrics?.impact_score || 0} ); })} {selectedEvent && ( {selectedEvent.event_title} {selectedEvent.event_type} {selectedEvent.event_date} 事件详情 {selectedEvent.event_desc} {selectedEvent.related_info?.financial_impact && ( 财务影响 {selectedEvent.related_info.financial_impact} )} 影响评估 影响度 70 ? 'red' : 'orange'} hasStripe isAnimated /> {selectedEvent.impact_metrics?.impact_score || 0}/100 {selectedEvent.impact_metrics?.is_positive ? '正面影响' : '负面影响'} )} ); }; // 股东类型标签组件 const ShareholderTypeBadge = ({ type }) => { const typeConfig = { '基金': { color: 'blue', icon: FaChartBar }, '个人': { color: 'green', icon: FaUserTie }, '法人': { color: 'purple', icon: FaBuilding }, 'QFII': { color: 'orange', icon: FaGlobe }, '社保': { color: 'red', icon: FaShieldAlt }, '保险': { color: 'teal', icon: FaShieldAlt }, '信托': { color: 'cyan', icon: FaBriefcase }, '券商': { color: 'pink', icon: FaChartLine } }; const config = Object.entries(typeConfig).find(([key]) => type?.includes(key))?.[1] || { color: 'gray', icon: FaCircle }; return ( {type} ); }; // 主组件 - 完整版 const CompanyAnalysisComplete = ({ stockCode: propStockCode }) => { const [stockCode, setStockCode] = useState(propStockCode || '000001'); const [loading, setLoading] = useState(false); // 监听props中的stockCode变化 useEffect(() => { if (propStockCode && propStockCode !== stockCode) { setStockCode(propStockCode); } }, [propStockCode, stockCode]); // 企业深度分析数据 const [comprehensiveData, setComprehensiveData] = useState(null); const [valueChainData, setValueChainData] = useState(null); const [keyFactorsData, setKeyFactorsData] = useState(null); // 股票概览数据 const [basicInfo, setBasicInfo] = useState(null); const [actualControl, setActualControl] = useState([]); const [concentration, setConcentration] = useState([]); const [management, setManagement] = useState([]); const [topCirculationShareholders, setTopCirculationShareholders] = useState([]); const [topShareholders, setTopShareholders] = useState([]); const [branches, setBranches] = useState([]); const [announcements, setAnnouncements] = useState([]); const [disclosureSchedule, setDisclosureSchedule] = useState([]); // 新闻动态数据 const [newsEvents, setNewsEvents] = useState([]); const [newsLoading, setNewsLoading] = useState(false); const [newsSearchQuery, setNewsSearchQuery] = useState(''); const [newsPagination, setNewsPagination] = useState({ page: 1, per_page: 10, total: 0, pages: 0, has_next: false, has_prev: false }); const [error, setError] = useState(null); const toast = useToast(); const bgColor = useColorModeValue('gray.50', 'gray.900'); const cardBg = useColorModeValue('white', 'gray.800'); const { isOpen: isAnnouncementOpen, onOpen: onAnnouncementOpen, onClose: onAnnouncementClose } = useDisclosure(); const [selectedAnnouncement, setSelectedAnnouncement] = useState(null); // 业务板块详情展开状态 const [expandedSegments, setExpandedSegments] = useState({}); // 切换业务板块展开状态 const toggleSegmentExpansion = (segmentIndex) => { setExpandedSegments(prev => ({ ...prev, [segmentIndex]: !prev[segmentIndex] })); }; // 加载数据 const loadData = async () => { setLoading(true); setError(null); try { const requests = [ // 深度分析数据 fetch(`${API_BASE_URL}/api/company/comprehensive-analysis/${stockCode}`).then(r => r.json()), fetch(`${API_BASE_URL}/api/company/value-chain-analysis/${stockCode}`).then(r => r.json()), fetch(`${API_BASE_URL}/api/company/key-factors-timeline/${stockCode}`).then(r => r.json()), // 股票概览数据 fetch(`${API_BASE_URL}/api/stock/${stockCode}/basic-info`).then(r => r.json()), fetch(`${API_BASE_URL}/api/stock/${stockCode}/actual-control`).then(r => r.json()), fetch(`${API_BASE_URL}/api/stock/${stockCode}/concentration`).then(r => r.json()), fetch(`${API_BASE_URL}/api/stock/${stockCode}/management?active_only=true`).then(r => r.json()), fetch(`${API_BASE_URL}/api/stock/${stockCode}/top-circulation-shareholders?limit=10`).then(r => r.json()), fetch(`${API_BASE_URL}/api/stock/${stockCode}/top-shareholders?limit=10`).then(r => r.json()), fetch(`${API_BASE_URL}/api/stock/${stockCode}/branches`).then(r => r.json()), fetch(`${API_BASE_URL}/api/stock/${stockCode}/announcements?limit=20`).then(r => r.json()), fetch(`${API_BASE_URL}/api/stock/${stockCode}/disclosure-schedule`).then(r => r.json()) ]; const [ comprehensiveRes, valueChainRes, keyFactorsRes, basicRes, actualRes, concentrationRes, managementRes, circulationRes, shareholdersRes, branchesRes, announcementsRes, disclosureRes ] = await Promise.all(requests); // 设置深度分析数据 if (comprehensiveRes.success) setComprehensiveData(comprehensiveRes.data); if (valueChainRes.success) setValueChainData(valueChainRes.data); if (keyFactorsRes.success) setKeyFactorsData(keyFactorsRes.data); // 设置股票概览数据 if (basicRes.success) setBasicInfo(basicRes.data); if (actualRes.success) setActualControl(actualRes.data); if (concentrationRes.success) setConcentration(concentrationRes.data); if (managementRes.success) setManagement(managementRes.data); if (circulationRes.success) setTopCirculationShareholders(circulationRes.data); if (shareholdersRes.success) setTopShareholders(shareholdersRes.data); if (branchesRes.success) setBranches(branchesRes.data); if (announcementsRes.success) setAnnouncements(announcementsRes.data); if (disclosureRes.success) setDisclosureSchedule(disclosureRes.data); } catch (err) { setError(err.message); logger.error('CompanyOverview', 'loadData', err, { stockCode }); // ❌ 移除数据加载失败toast // toast({ // title: '数据加载失败', // description: err.message, // status: 'error', // duration: 3000, // isClosable: true, // }); } finally { setLoading(false); } }; useEffect(() => { if (stockCode) { loadData(); } }, [stockCode]); // 加载新闻事件 const loadNewsEvents = async (page = 1, searchQuery = '') => { setNewsLoading(true); try { // 构建查询参数 const params = new URLSearchParams({ page: page.toString(), per_page: '10', sort: 'new', include_creator: 'true', include_stats: 'true' }); // 搜索关键词优先级: // 1. 用户输入的搜索关键词 // 2. 股票简称 const queryText = searchQuery || basicInfo?.SECNAME || ''; if (queryText) { params.append('q', queryText); } const response = await fetch(`${API_BASE_URL}/api/events?${params.toString()}`); const data = await response.json(); // API返回 data.data.events const events = data.data?.events || data.events || []; const pagination = data.data?.pagination || { page: 1, per_page: 10, total: 0, pages: 0, has_next: false, has_prev: false }; setNewsEvents(events); setNewsPagination(pagination); } catch (err) { logger.error('CompanyOverview', 'loadNewsEvents', err, { stockCode, searchQuery, page }); setNewsEvents([]); setNewsPagination({ page: 1, per_page: 10, total: 0, pages: 0, has_next: false, has_prev: false }); } finally { setNewsLoading(false); } }; // 当基本信息加载完成后,加载新闻事件 useEffect(() => { if (basicInfo) { loadNewsEvents(1); } }, [basicInfo]); // 处理搜索 const handleNewsSearch = () => { loadNewsEvents(1, newsSearchQuery); }; // 处理分页 const handleNewsPageChange = (newPage) => { loadNewsEvents(newPage, newsSearchQuery); // 滚动到新闻列表顶部 document.getElementById('news-list-top')?.scrollIntoView({ behavior: 'smooth' }); }; // 管理层职位分类 const getManagementByCategory = () => { const categories = { '高管': [], '董事': [], '监事': [], '其他': [] }; management.forEach(person => { if (person.position_category === '高管' || person.position_name?.includes('总')) { categories['高管'].push(person); } else if (person.position_category === '董事' || person.position_name?.includes('董事')) { categories['董事'].push(person); } else if (person.position_category === '监事' || person.position_name?.includes('监事')) { categories['监事'].push(person); } else { categories['其他'].push(person); } }); return categories; }; // 计算股权集中度变化 const getConcentrationTrend = () => { const grouped = {}; concentration.forEach(item => { if (!grouped[item.end_date]) { grouped[item.end_date] = {}; } grouped[item.end_date][item.stat_item] = item; }); return Object.entries(grouped).sort((a, b) => b[0].localeCompare(a[0])).slice(0, 5); }; // 生成雷达图配置 const getRadarChartOption = () => { if (!comprehensiveData?.competitive_position?.scores) return null; const scores = comprehensiveData.competitive_position.scores; const indicators = [ { name: '市场地位', max: 100 }, { name: '技术实力', max: 100 }, { name: '品牌价值', max: 100 }, { name: '运营效率', max: 100 }, { name: '财务健康', max: 100 }, { name: '创新能力', max: 100 }, { name: '风险控制', max: 100 }, { name: '成长潜力', max: 100 } ]; const data = [ scores.market_position || 0, scores.technology || 0, scores.brand || 0, scores.operation || 0, scores.finance || 0, scores.innovation || 0, scores.risk || 0, scores.growth || 0 ]; return { tooltip: { trigger: 'item' }, radar: { indicator: indicators, shape: 'polygon', splitNumber: 4, name: { textStyle: { color: '#666', fontSize: 12 } }, splitLine: { lineStyle: { color: ['#e8e8e8', '#e0e0e0', '#d0d0d0', '#c0c0c0'] } }, splitArea: { show: true, areaStyle: { color: ['rgba(250,250,250,0.3)', 'rgba(200,200,200,0.3)'] } }, axisLine: { lineStyle: { color: '#ddd' } } }, series: [{ name: '竞争力评分', type: 'radar', data: [{ value: data, name: '当前评分', symbol: 'circle', symbolSize: 5, lineStyle: { width: 2, color: '#3182ce' }, areaStyle: { color: 'rgba(49, 130, 206, 0.3)' }, label: { show: true, formatter: (params) => params.value, color: '#3182ce', fontSize: 10 } }] }] }; }; // 生成产业链桑基图配置 const getSankeyChartOption = () => { if (!valueChainData?.value_chain_flows || valueChainData.value_chain_flows.length === 0) return null; const nodes = new Set(); const links = []; valueChainData.value_chain_flows.forEach(flow => { // 检查 source 和 target 是否存在 if (!flow?.source?.node_name || !flow?.target?.node_name) return; nodes.add(flow.source.node_name); nodes.add(flow.target.node_name); links.push({ source: flow.source.node_name, target: flow.target.node_name, value: parseFloat(flow.flow_metrics?.flow_ratio) || 1, lineStyle: { color: 'source', opacity: 0.6 } }); }); return { tooltip: { trigger: 'item', triggerOn: 'mousemove' }, series: [{ type: 'sankey', layout: 'none', emphasis: { focus: 'adjacency' }, data: Array.from(nodes).map(name => ({ name })), links: links, lineStyle: { color: 'gradient', curveness: 0.5 }, label: { color: '#333', fontSize: 10 } }] }; }; if (loading) { return (
正在加载企业全景数据...
); } return ( {/* 公司头部信息 - 醒目展示 */} {basicInfo && ( {basicInfo.ORGNAME || basicInfo.SECNAME} {basicInfo.SECCODE} {basicInfo.sw_industry_l1} {basicInfo.sw_industry_l2} {basicInfo.sw_industry_l3 && ( {basicInfo.sw_industry_l3} )} 法定代表人: {basicInfo.legal_representative} 董事长: {basicInfo.chairman} 总经理: {basicInfo.general_manager} 成立日期: {formatUtils.formatDate(basicInfo.establish_date)} {basicInfo.company_intro} 注册资本 {formatUtils.formatRegisteredCapital(basicInfo.reg_capital)} {basicInfo.province} {basicInfo.city} {basicInfo.website} {basicInfo.email} {basicInfo.tel} )} {/* 主要内容区 - 分为深度分析、基本信息和新闻动态 */} 深度分析 基本信息 新闻动态 {/* 深度分析标签页 */} {/* 核心定位卡片 */} {comprehensiveData?.qualitative_analysis && ( 核心定位 {comprehensiveData.qualitative_analysis.core_positioning?.one_line_intro && ( {comprehensiveData.qualitative_analysis.core_positioning.one_line_intro} )} 投资亮点 {comprehensiveData.qualitative_analysis.core_positioning?.investment_highlights || '暂无数据'} 商业模式 {comprehensiveData.qualitative_analysis.core_positioning?.business_model_desc || '暂无数据'} )} {/* 竞争地位分析 */} {comprehensiveData?.competitive_position && ( 竞争地位分析 {comprehensiveData.competitive_position.ranking && ( 行业排名 {comprehensiveData.competitive_position.ranking.industry_rank}/{comprehensiveData.competitive_position.ranking.total_companies} )} {comprehensiveData.competitive_position.analysis?.main_competitors && ( 主要竞争对手 {comprehensiveData.competitive_position.analysis.main_competitors .split(',') .map((competitor, idx) => ( {competitor.trim()} ))} )} {getRadarChartOption() && ( )} 竞争优势 {comprehensiveData.competitive_position.analysis?.competitive_advantages || '暂无数据'} 竞争劣势 {comprehensiveData.competitive_position.analysis?.competitive_disadvantages || '暂无数据'} )} {/* 业务结构分析 */} {comprehensiveData?.business_structure && comprehensiveData.business_structure.length > 0 && ( 业务结构分析 {comprehensiveData.business_structure[0]?.report_period} {comprehensiveData.business_structure.map((business, idx) => ( ))} )} {/* 产业链分析 */} {valueChainData && ( 产业链分析 上游 {valueChainData.analysis_summary?.upstream_nodes || 0} 核心 {valueChainData.analysis_summary?.company_nodes || 0} 下游 {valueChainData.analysis_summary?.downstream_nodes || 0} 层级视图 流向关系 {(valueChainData.value_chain_structure?.nodes_by_level?.['level_-2'] || valueChainData.value_chain_structure?.nodes_by_level?.['level_-1']) && ( 上游供应链 原材料与供应商 {[ ...(valueChainData.value_chain_structure?.nodes_by_level?.['level_-2'] || []), ...(valueChainData.value_chain_structure?.nodes_by_level?.['level_-1'] || []) ].map((node, idx) => ( ))} )} {valueChainData.value_chain_structure?.nodes_by_level?.['level_0'] && ( 核心企业 公司主体与产品 {valueChainData.value_chain_structure.nodes_by_level['level_0'].map((node, idx) => ( ))} )} {(valueChainData.value_chain_structure?.nodes_by_level?.['level_1'] || valueChainData.value_chain_structure?.nodes_by_level?.['level_2']) && ( 下游客户 客户与终端市场 {[ ...(valueChainData.value_chain_structure?.nodes_by_level?.['level_1'] || []), ...(valueChainData.value_chain_structure?.nodes_by_level?.['level_2'] || []) ].map((node, idx) => ( ))} )} {getSankeyChartOption() ? ( ) : (
暂无流向数据
)}
)} {/* 关键因素与发展时间线 */} {keyFactorsData?.key_factors && ( 关键因素 {keyFactorsData.key_factors.total_factors} 项 {keyFactorsData.key_factors.categories.map((category, idx) => ( {category.category_name} {category.factors.length} {category.factors.map((factor, fidx) => ( ))} ))} )} {keyFactorsData?.development_timeline && ( 发展时间线 正面 {keyFactorsData.development_timeline.statistics?.positive_events || 0} 负面 {keyFactorsData.development_timeline.statistics?.negative_events || 0} )} {/* 业务板块详情 */} {comprehensiveData?.business_segments && comprehensiveData.business_segments.length > 0 && ( 业务板块详情 {comprehensiveData.business_segments.length} 个板块 {comprehensiveData.business_segments.map((segment, idx) => { const isExpanded = expandedSegments[idx]; return ( {segment.segment_name} 业务描述 {segment.segment_description || '暂无描述'} 竞争地位 {segment.competitive_position || '暂无数据'} 未来潜力 {segment.future_potential || '暂无数据'} {isExpanded && segment.key_products && ( 主要产品 {segment.key_products} )} {isExpanded && segment.market_share && ( 市场份额 {segment.market_share}% )} {isExpanded && segment.revenue_contribution && ( 营收贡献 {segment.revenue_contribution}% )} ); })} )} {/* 战略分析 */} {comprehensiveData?.qualitative_analysis?.strategy && ( 战略分析 战略方向 {comprehensiveData.qualitative_analysis.strategy.strategy_description || '暂无数据'} 战略举措 {comprehensiveData.qualitative_analysis.strategy.strategic_initiatives || '暂无数据'} )}
{/* 基本信息标签页 */} 股权结构 管理团队 公司公告 分支机构 工商信息 {/* 股权结构标签页 */} {actualControl.length > 0 && ( 实际控制人 {actualControl[0].actual_controller_name} {actualControl[0].control_type} 截至 {formatUtils.formatDate(actualControl[0].end_date)} 控制比例 {formatUtils.formatPercentage(actualControl[0].holding_ratio)} {formatUtils.formatShares(actualControl[0].holding_shares)} )} {concentration.length > 0 && ( 股权集中度 {getConcentrationTrend().slice(0, 1).map(([date, items]) => ( {formatUtils.formatDate(date)} {Object.entries(items).map(([key, item]) => ( {item.stat_item} {formatUtils.formatPercentage(item.holding_ratio)} {item.ratio_change && ( 0 ? 'red' : 'green'}> 0 ? FaArrowUp : FaArrowDown} mr={1} boxSize={3} /> {Math.abs(item.ratio_change).toFixed(2)}% )} ))} ))} )} {topShareholders.length > 0 && ( 十大股东 {formatUtils.formatDate(topShareholders[0].end_date)} {topShareholders.slice(0, 10).map((shareholder, idx) => ( ))}
排名 股东名称 股东类型 持股数量 持股比例 股份性质
{shareholder.shareholder_rank} {shareholder.shareholder_name} {formatUtils.formatShares(shareholder.holding_shares)} {formatUtils.formatPercentage(shareholder.total_share_ratio)} {shareholder.share_nature || '流通股'}
)} {topCirculationShareholders.length > 0 && ( 十大流通股东 {formatUtils.formatDate(topCirculationShareholders[0].end_date)} {topCirculationShareholders.slice(0, 10).map((shareholder, idx) => ( ))}
排名 股东名称 股东类型 持股数量 流通股比例
{shareholder.shareholder_rank} {shareholder.shareholder_name} {formatUtils.formatShares(shareholder.holding_shares)} {formatUtils.formatPercentage(shareholder.circulation_share_ratio)}
)}
{/* 管理团队标签页 */} {Object.entries(getManagementByCategory()).map(([category, people]) => ( people.length > 0 && ( {category} {people.length}人 {people.map((person, idx) => ( {person.name} {person.gender && ( )} {person.position_name} {person.education && ( {person.education} )} {person.birth_year && ( {new Date().getFullYear() - parseInt(person.birth_year)}岁 )} {person.nationality && person.nationality !== '中国' && ( {person.nationality} )} 任职日期:{formatUtils.formatDate(person.start_date)} ))} ) ))} {/* 公司公告标签页 */} {disclosureSchedule.length > 0 && ( 财报披露日程 {disclosureSchedule.slice(0, 4).map((schedule, idx) => ( {schedule.report_name} {schedule.is_disclosed ? '已披露' : '预计'} {formatUtils.formatDate( schedule.is_disclosed ? schedule.actual_date : schedule.latest_scheduled_date )} ))} )} 最新公告 {announcements.map((announcement, idx) => ( { setSelectedAnnouncement(announcement); onAnnouncementOpen(); }} _hover={{ bg: 'gray.50' }} > {announcement.info_type || '公告'} {formatUtils.formatDate(announcement.announce_date)} {announcement.title} {announcement.format && ( {announcement.format} )} } variant="ghost" onClick={(e) => { e.stopPropagation(); window.open(announcement.url, '_blank'); }} /> ))} {/* 分支机构标签页 */} {branches.length > 0 ? ( {branches.map((branch, idx) => ( {branch.branch_name} {branch.business_status} 注册资本 {branch.register_capital || '-'} 法人代表 {branch.legal_person || '-'} 成立日期 {formatUtils.formatDate(branch.register_date)} 关联企业 {branch.related_company_count || 0} 家 ))} ) : (
暂无分支机构信息
)}
{/* 工商信息标签页 */} {basicInfo && ( 工商信息 统一信用代码 {basicInfo.credit_code} 公司规模 {basicInfo.company_size} 注册地址 {basicInfo.reg_address} 办公地址 {basicInfo.office_address} 服务机构 会计师事务所 {basicInfo.accounting_firm} 律师事务所 {basicInfo.law_firm} 主营业务 {basicInfo.main_business} 经营范围 {basicInfo.business_scope} )}
{/* 新闻动态标签页 */} {/* 搜索框和统计信息 */} setNewsSearchQuery(e.target.value)} onKeyPress={(e) => e.key === 'Enter' && handleNewsSearch()} /> {newsPagination.total > 0 && ( 共找到 {newsPagination.total} 条新闻 )}
{/* 新闻列表 */} {newsLoading ? (
正在加载新闻...
) : newsEvents.length > 0 ? ( <> {newsEvents.map((event, idx) => { const importanceColor = { 'S': 'red', 'A': 'orange', 'B': 'yellow', 'C': 'green' }[event.importance] || 'gray'; const eventTypeIcon = { '企业公告': FaBullhorn, '政策': FaGavel, '技术突破': FaFlask, '企业融资': FaDollarSign, '政策监管': FaShieldAlt, '政策动态': FaFileAlt, '行业事件': FaIndustry }[event.event_type] || FaNewspaper; return ( {/* 标题栏 */} {event.title} {/* 标签栏 */} {event.importance && ( {event.importance}级 )} {event.event_type && ( {event.event_type} )} {event.invest_score && ( 投资分: {event.invest_score} )} {event.keywords && event.keywords.length > 0 && ( <> {event.keywords.slice(0, 4).map((keyword, kidx) => ( {typeof keyword === 'string' ? keyword : (keyword?.concept || keyword?.name || '未知')} ))} )} {/* 右侧信息栏 */} {event.created_at ? new Date(event.created_at).toLocaleDateString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit' }) : ''} {event.view_count !== undefined && ( {event.view_count} )} {event.hot_score !== undefined && ( {event.hot_score.toFixed(1)} )} {event.creator && ( @{event.creator.username} )} {/* 描述 */} {event.description && ( {event.description} )} {/* 收益率数据 */} {(event.related_avg_chg !== null || event.related_max_chg !== null || event.related_week_chg !== null) && ( 相关涨跌: {event.related_avg_chg !== null && event.related_avg_chg !== undefined && ( 平均 0 ? 'red.500' : 'green.500'} > {event.related_avg_chg > 0 ? '+' : ''}{event.related_avg_chg.toFixed(2)}% )} {event.related_max_chg !== null && event.related_max_chg !== undefined && ( 最大 0 ? 'red.500' : 'green.500'} > {event.related_max_chg > 0 ? '+' : ''}{event.related_max_chg.toFixed(2)}% )} {event.related_week_chg !== null && event.related_week_chg !== undefined && ( 0 ? 'red.500' : 'green.500'} > {event.related_week_chg > 0 ? '+' : ''}{event.related_week_chg.toFixed(2)}% )} )} ); })} {/* 分页控件 */} {newsPagination.pages > 1 && ( {/* 分页信息 */} 第 {newsPagination.page} / {newsPagination.pages} 页 {/* 分页按钮 */} {/* 页码按钮 */} {(() => { const currentPage = newsPagination.page; const totalPages = newsPagination.pages; const pageButtons = []; // 显示当前页及前后各2页 let startPage = Math.max(1, currentPage - 2); let endPage = Math.min(totalPages, currentPage + 2); // 如果开始页大于1,显示省略号 if (startPage > 1) { pageButtons.push( ... ); } for (let i = startPage; i <= endPage; i++) { pageButtons.push( ); } // 如果结束页小于总页数,显示省略号 if (endPage < totalPages) { pageButtons.push( ... ); } return pageButtons; })()} )} ) : (
暂无相关新闻 {newsSearchQuery ? '尝试修改搜索关键词' : '该公司暂无新闻动态'}
)} {/* 公告详情模态框 */} {selectedAnnouncement?.title} {selectedAnnouncement?.info_type} {formatUtils.formatDate(selectedAnnouncement?.announce_date)} 文件格式:{selectedAnnouncement?.format} 文件大小:{selectedAnnouncement?.file_size} KB ); }; export default CompanyAnalysisComplete;